摘要:緩沖區的容量不可能為負值,創建后不能改變界限界限第一個不應該被讀寫或者寫入的緩沖區位置索引。當使用從中讀取數據時,的值恰好等于已經讀到了多少數據。
NIO:New IO
Java新IO概述新IO采用內存映射文件的方式來處理輸入/輸出,新IO文件或文件的一段區域映射到內存中,這樣就可以訪問內存一樣來訪問文件了(這種方式模擬了操作系統上的虛擬內存的概念),通過這種方式來進行輸入/輸出比傳統的輸入/輸出要快得多
Java中NIO相關的包如下:
java.nio包:主要提供了一些和Buffer相關的類
java.nio.channels包:主要包括Channel和Selector相關的類
java.nio.charset包:主要包含和字符集相關的類
java.nio.channels.spi包:主要包含提供Channel服務的類
java.nio.charset.spi包:主要包含提供字符集服務的相關類
Channel(通道)和Buffer(緩沖)是新IO中的兩個核心對象,Channel是對傳統輸入/輸出系統中的模擬,在新IO系統中所有數據都需要通過通道傳輸;Channel與傳統的InputStream、OutputStream最大的區別在于它提供了一個map方法,通過該map方法可以直接將“一塊數據”映射到內存中。如果說傳統的輸入/輸出系統是面向流的處理,而新IO則是面向塊的處理
Buffer可以被理解成一個容器,它的本質是一個數組,發送到Channel中的所有對象都必須首先放到Buffer中,而從Channel中讀取的數據也必須先讀到Buffer中。此處的Buffer有點類似于前面我們介紹的“竹筒”,但該Buffer既可以像前面那樣一次、一次去Channel中取水,也允許使用Channel直接將文件的某塊數據映射成Buffer
除了Channel和Buffer之外,新IO還提供了用于將UNICODE字符串映射成字節序列以及逆映射操作的Charset類,還提供了用于支持非阻塞式輸入/輸出的Selector類
使用BufferBuffer類沒有提供構造器,通過使用如下方法來得到一個Buffer對象:
static XxxBuffer allocate(int capacity):創建一個容量為capacity的XxxBuffer對象
使用較多的是ByteBuffer和CharBuffer。其中ByteBuffer類還有一個子類:MappedByteBuffer,它用于表示Channel將磁盤文件的部分或全部內容映射到內存中后得到的結果,通常MappedByteBuffer對象由Channel的map()方法返回
Buffer三個重要概念:容量(capacity)、界限(limit)、位置(position)
容量(capacity):緩沖區的容量(capacity)表示該Buffer的最大數據容量,即最多可以存儲多少數據。緩沖區的容量不可能為負值,創建后不能改變
界限(limit)
界限(limit):第一個不應該被讀寫或者寫入的緩沖區位置索引。也就是說,位于limit后的數據既不可被讀,也不可被寫
位置(position):用于指明下一個可以被讀出或者寫入的緩沖區位置索引(類似于IO流中的記錄指針)。當使用Buffer從Channel中讀取數據時,position的值恰好等于已經讀到了多少數據。當剛剛新建一個Buffer對象時,其position為0;如果從Channel中讀取了2個數據到該Buffer中,則position為2,指向Buffer中的第三個(第1個位置的索引為0)位置
標記(mark):Buffer里還支持一個可選的標記(mark,類似于傳統IO流中的mark),Buffer允許直接將position定位到該mark處。
0 <= mark <= position <= limit <= capacity
Buffer的主要作用就是裝入數據,然后輸出數據,開始時Buffer的position為0,limit為capacity,程序可通過put()方法向Buffer中放入一些數據(或從channel獲取數據),每放入一些數據,position向后移動一些位置
當Buffer裝入數據結束后,調用filp()方法,該方法將limit設置為position所在位置,將position設置為0。這樣使得從Buffer中讀取數據總是從0開始。讀完所有裝入的數據即結束,也就是說,Buffer調用filp后,Buffer為輸出數據做好了準備
當Buffer輸出數據結束后,調用clear方法。將position置為0,將limit置為capacity,這樣為再次向Buffer中裝載數據做好準備
Buffer抽象類常用方法:
int capacity():返回Buffer的capacity大小
boolean hasRemaining():判斷當前位置(position)和界限(limit)之間是否有元素可供處理
int limit():返回Buffer的界限(limit)的位置
Buffer limit(int newLimit):重新設置界限(limit)的值,并返回一個具有新的limit的緩沖區對象
int position():返回Buffer的position值
Buffer position(new position):設置Buffer的position值,并返回position被修改后的Buffer對象
int remaining():返回當前位置和界限(limit)之間的元素個數
Buffer reset():將位置(position)轉到mark所在的位置
Buffer rewind():將位置(position)設置為0,取消設置的mark
put()和get()方法,用于向Buffer中放入數據和從Buffer中取出數據。當使用put()和get()。Buffer既支持對單個數據的訪問,也支持對批量數據的訪問(以數組作為參數)
當使用put()和get()來訪問Buffer中的數據時,分為相對和絕對兩種:
相對(Relative):從Buffer當前位置讀取或寫入數據,然后將位置(position)的值按處理元素個數增加
絕對(Absolute):直接根據索引來向Buffer中讀取或寫入數據,使用絕對方式來訪問Buffer里的數據,并不會影響position的值
import java.nio.*; public class BufferTest { public static void main(String[] args) { // 創建Buffer CharBuffer buff = CharBuffer.allocate(8); // ① System.out.println("capacity: " + buff.capacity()); System.out.println("limit: " + buff.limit()); System.out.println("position: " + buff.position()); // 放入元素 buff.put("a"); buff.put("b"); buff.put("c"); // ② System.out.println("加入三個元素后,position = " + buff.position()); // 調用flip()方法 buff.flip(); // ③ System.out.println("執行flip()后,limit = " + buff.limit()); System.out.println("position = " + buff.position()); // 取出第一個元素 System.out.println("第一個元素(position=0):" + buff.get()); // ④ System.out.println("取出一個元素后,position = " + buff.position()); // 調用clear方法 buff.clear(); // ⑤ System.out.println("執行clear()后,limit = " + buff.limit()); System.out.println("執行clear()后,position = " + buff.position()); System.out.println("執行clear()后,緩沖區內容并沒有被清除:" + "第三個元素為:" + buff.get(2)); // ⑥ System.out.println("執行絕對讀取后,position = " + buff.position()); } }
運行結果:
capacity: 8 limit: 8 position: 0 加入三個元素后,position = 3 執行flip()后,limit = 3 position = 0 第一個元素(position=0):a 取出一個元素后,position = 1 執行clear()后,limit = 8 執行clear()后,position = 0 執行clear()后,緩沖區內容并沒有被清除:第三個元素為:c 執行絕對讀取后,position = 0
代碼①:新分配的CharBuffer對象:
代碼②:向Buffer中放入3個對象后
代碼③:執行Buffer的flip()方法后
代碼⑤:執行clear()后的Buffer
使用ChannelChannel類似于傳統的流對象,但與傳統的流對象有兩個主要區別:
Channel可以直接將指定文件的部分或全部直接映射成Buffer
程序不能直接訪問Channel中的數據,包括讀、寫入都不行,Channel只能與Buffer進行交互。也就是說,如果要從Channel中取得數據,必須先用Buffer從Channel中取出一些數據,然后讓程序從Buffer中取出這些數據;如果要將程序中的數據寫入Channel,一樣先讓程序將誰放入Buffer中,程序再將Buffer里的數據寫入Channel中
所有的Channel都不應該通過構造器來直接創建,而是通過傳統的節點InputStream、OutputStream的getChannel()方法來返回對應的Channel,不同的節點流獲得的Channle不一樣
Channel中最常用的三類方法是map()、read()和write()
map()方法用于將Channel對應的部分或全部數據映射成ByteBuffer;而read()或write()方法都有一系列重載形式,這些方法用于從Buffer中讀取數據或向Buffer里寫入數據
map方法的方法簽名為:MappedByteBuffer map(FileChannel.MapMode mode, long position, long size),第一個參數執行映射時的模式,分別有只讀,讀寫模式,而第二個,第三個參數用于控制將Channel的哪些數據映射成ByteBuffer
以下是直接將FileChannel的全部數據映射成ByteBuffer的效果的代碼。使用FileInputStream、FileOutputStream來獲取FileChannel。代碼①直接將指定Channel中的全部數據映射成ByteBuffer,代碼②直接將整個ByteBuffer的全部數據寫入一個輸出FileChannel中,完成文件復制。使用Charset類和CharsetDecoder類將ByteBuffer轉換成CharBuffer
import java.io.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; public class FileChannelTest { public static void main(String[] args) { File f = new File("FileChannelTest.java"); try( // 創建FileInputStream,以該文件輸入流創建FileChannel FileChannel inChannel = new FileInputStream(f).getChannel(); // 以文件輸出流創建FileBuffer,用以控制輸出 FileChannel outChannel = new FileOutputStream("a.txt").getChannel()) { // 將FileChannel里的全部數據映射成ByteBuffer MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length()); // ① // 使用GBK的字符集來創建解碼器 Charset charset = Charset.forName("GBK"); // 直接將buffer里的數據全部輸出 outChannel.write(buffer); // ② // 再次調用buffer的clear()方法,復原limit、position的位置 buffer.clear(); // 創建解碼器(CharsetDecoder)對象 CharsetDecoder decoder = charset.newDecoder(); // 使用解碼器將ByteBuffer轉換成CharBuffer CharBuffer charBuffer = decoder.decode(buffer); // CharBuffer的toString方法可以獲取對應的字符串 System.out.println(charBuffer); } catch (IOException ex) { ex.printStackTrace(); } } }
RandomAccessFile中也包含getChannel()方法,返回的FileChannel()讀寫類型取決于RandomAccessFile打開文件的模式。以下代碼將對a.txt文件的內容進行復制,追加到該文件后面:
import java.io.*; import java.nio.*; import java.nio.channels.*; public class RandomFileChannelTest { public static void main(String[] args) throws IOException { File f = new File("a.txt"); try( // 創建一個RandomAccessFile對象 RandomAccessFile raf = new RandomAccessFile(f, "rw"); // 獲取RandomAccessFile對應的Channel FileChannel randomChannel = raf.getChannel()) { // 將Channel中所有數據映射成ByteBuffer ByteBuffer buffer = randomChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length()); // 把Channel的記錄指針移動到最后 randomChannel.position(f.length()); // 將buffer中所有數據輸出 randomChannel.write(buffer); } } }
randomChannel.position(f.length()); 代碼將Channel的記錄指針移動到該Channel的最后,從而可以讓程序將指定ByteBuffer的數據追加到該Channel后面。每次運行上面程序,都會把a.txt文件的內容復制一份,并將全部內容追加到該文件的后面
使用map()方法一次將所有的文件內容映射到內存中引起性能下降,可以使用Channel和Buffer傳統的“用竹筒多次重復取水”的方式:
import java.io.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; public class ReadFile { public static void main(String[] args) throws IOException { try( // 創建文件輸入流 FileInputStream fis = new FileInputStream("ReadFile.java"); // 創建一個FileChannel FileChannel fcin = fis.getChannel()) { // 定義一個ByteBuffer對象,用于重復取水 ByteBuffer bbuff = ByteBuffer.allocate(256); // 將FileChannel中數據放入ByteBuffer中 while( fcin.read(bbuff) != -1 ) { // 鎖定Buffer的空白區 bbuff.flip(); // 創建Charset對象 Charset charset = Charset.forName("GBK"); // 創建解碼器(CharsetDecoder)對象 CharsetDecoder decoder = charset.newDecoder(); // 將ByteBuffer的內容轉碼 CharBuffer cbuff = decoder.decode(bbuff); System.out.print(cbuff); // 將Buffer初始化,為下一次讀取數據做準備 bbuff.clear(); } } } }
Buffer提供了flip()和clear()兩個方法,每次讀取數后調用flip()方法將沒有數據的區域“封印”起來,避免程序從Buffer中取出null值;數據取出后立即調用clear()方法將Buffer的position設0,為下一次讀取數據做準備
字符集和Charset編碼Encode:把明文的字符序列換成計算機理解的二進制序列
解碼Decode:把二進制序列轉換成明文字符串
Java默認使用Unicode字符集,但很多操作系統并不使用Unicode字符集,那么當從系統中讀取數據到Java程序中時,就可能出現亂碼等問題
JDK1.4提供了Charset來處理字節序列和字符序列(字符串)之間的轉換關系,該類包含了用于創建編碼和解碼的的方法,還提供了獲取所有Charset所支持的字符集的方法,Charset類是不可變的
availableCharset()的靜態方法用于獲取當前JDK所支持的所有字符集
import java.nio.charset.*; import java.util.*; public class CharsetTest { public static void main(String[] args) { // 獲取Java支持的全部字符集 SortedMapmap = Charset.availableCharsets(); for (String alias : map.keySet()) { // 輸出字符集的別名和對應的Charset對象 System.out.println(alias + "----->" + map.get(alias)); } } }
常用字符串別名:
GBK:簡體中文字符串
BIG5:繁體中文字符串
ISO-8859-1:ISO拉丁字母表No.1
UTF-8:8位UCS轉換格式
UTF-16BE:16位的UCS轉換格式,Big-endian(最低地址存放高位字節)字節順序
UTF-16LE:16位的UCS轉換格式,Little-endian(最高地址存放低位字節)字節順序
UTF-16:16位的UCS轉換格式,字節順序由可選的字節順序標記來標識
調用Charset的forName()方法創建字符串別名對應的Charset對象,forName()方法的參數就是相應字符集的別名:
Charset cs = Charset.forName("ISO-8859-1");
獲得Charset對象之后,通過該對象的newDecoder()、newEncoder()方法分別返回CharsetDecoder和CharsetEncoder對象,代表該Charset的解碼器和編碼器。調用CharsetDecoder的decode()方法可以將ByteBuffer(字節序列)轉換成CharBuffer(字符序列),調用CharsetEncoder的encode()方法可以將CharBuffer或String(字符序列)轉換成ByteBuffer(字節序列)
import java.nio.*; import java.nio.charset.*; public class CharsetTransform { public static void main(String[] args) throws Exception { // 創建簡體中文對應的Charset Charset cn = Charset.forName("GBK"); // 獲取cn對象對應的編碼器和解碼器 CharsetEncoder cnEncoder = cn.newEncoder(); CharsetDecoder cnDecoder = cn.newDecoder(); // 創建一個CharBuffer對象 CharBuffer cbuff = CharBuffer.allocate(8); cbuff.put("內"); cbuff.put("馬"); cbuff.put("爾"); cbuff.flip(); // 將CharBuffer中的字符序列轉換成字節序列 ByteBuffer bbuff = cnEncoder.encode(cbuff); // 循環訪問ByteBuffer中的每個字節 for (int i = 0; i < bbuff.capacity() ; i++) { System.out.print(bbuff.get(i) + " "); } // 將ByteBuffer的數據解碼成字符序列 System.out.println(" " + cnDecoder.decode(bbuff)); } }
Charset類提供了如下三個方法:
CharBuffer decode(ByteBuffer bb):將ByteBuffer中的字節序列轉換成字符序列的便捷方法
ByteBuffer encode(CharBuffer cb):將CharBuffer中的字節序列轉換成字符序列的便捷方法
ByteBuffer encode(String str):將String中的字節序列轉換成字符序列的便捷方法
獲取Charset對象后,如果僅僅需要進行簡單的編碼、解碼操作,實則無須創建CharsetDecoder和CharsetEncoder對象,直接調用Charset的encode()和decode()方法進行編碼、解碼即可
文件鎖如果多個運行的程序需要并發修改同一個文件時,程序之間需要某種機制來進行通信,使用文件鎖可以有效阻止多個進程并發修改同一個文件
Java提供了FileLock類支持文件鎖功能,在FileChannel中提供的lock()/tryLock()方法可以獲得文件鎖FileLock對象,從而鎖定文件
lock()方法和trylock()方法的區別是:當lock()試圖鎖定某個文件時,如果無法得到文件鎖,程序將一直阻塞,而tryLock()方法時嘗試鎖定文件,它將直接返回而不是阻塞,如果獲得了文件鎖,該方法則返回該文件鎖,否則將返回null
lock(long position, long size, boolean shared):對文件從position開始,長度為size的內容加鎖,該方法是阻塞式的
tryLock(long position, long size, boolean shared):非阻塞式的加鎖方法
當shared為true時,表明該鎖是一個共享鎖,它將允許多個進程來讀取文件,但不允許其他進程將其設為排他鎖;當shared為false的時,表明這是一個排他鎖,它將鎖住對該文件的讀寫
通過調用FileLock的isShared來判斷獲得的鎖是否為共享鎖
直接使用lock()或tryLock()方法獲取的文件鎖是排他鎖
處理完成之后,調用FileLock的release()方法釋放文件鎖
import java.io.*; import java.nio.*; import java.nio.channels.*; public class FileLockTest { public static void main(String[] args) throws Exception { try( // 使用FileOutputStream獲取FileChannel FileChannel channel = new FileOutputStream("a.txt").getChannel()) { // 使用非阻塞式方式對指定文件加鎖 FileLock lock = channel.tryLock(); // 程序暫停10s Thread.sleep(10000); // 釋放鎖 lock.release(); } } }Java7的NIO2
NIO的改進主要包括如下方面:
提供了全面的文件IO和文件系統訪問支持
基于異步Channel的IO
Path、Paths和File核心APIPaths提供了get(String first, String... more)方法來獲取Path對象,Paths會將給定的多個字符串連綴成路徑,如Paths.get("D:", "java","code")將返回D:javacode路徑;getNameCount()返回Path路徑所包含的路徑名
import java.io.*; import java.net.*; import java.nio.file.*; public class PathTest { public static void main(String[] args) throws Exception { // 以當前路徑來創建Path對象 Path path = Paths.get("."); System.out.println("path里包含的路徑數量:" + path.getNameCount()); System.out.println("path的根路徑:" + path.getRoot()); // 獲取path對應的絕對路徑 Path absolutePath = path.toAbsolutePath(); System.out.println(absolutePath); // 獲取絕對路徑的根路徑 System.out.println("absolutePath的根路徑:" + absolutePath.getRoot()); // 獲取絕對路徑所包含的路徑數量 System.out.println("absolutePath里包含的路徑數量:" + absolutePath.getNameCount()); System.out.println(absolutePath.getName(3)); // 以多個String來構建Path對象 Path path2 = Paths.get("D:", "java","code"); System.out.println(path2); } }
運行結果:
path里包含的路徑數量:1 path的根路徑:null D:DevelopmenteclipseworkspaceCrazyJava. absolutePath的根路徑:D: absolutePath里包含的路徑數量:5 CrazyJava D:javacode
以下代碼示范Files工具類的用法:
import java.nio.file.*; import java.nio.charset.*; import java.io.*; import java.util.*; public class FilesTest { public static void main(String[] args) throws Exception { // 復制文件 Files.copy(Paths.get("FilesTest.java"), new FileOutputStream("a.txt")); // 判斷FilesTest.java文件是否為隱藏文件 System.out.println("FilesTest.java是否為隱藏文件:"+ Files.isHidden(Paths.get("FilesTest.java"))); // 一次性讀取FilesTest.java文件的所有行 List使用FileVisitor遍歷文件和目錄lines = Files.readAllLines(Paths.get("FilesTest.java"), Charset.forName("gbk")); System.out.println(lines); // 判斷指定文件的大小 System.out.println("FilesTest.java的大小為:" + Files.size(Paths.get("FilesTest.java"))); List poem = new ArrayList<>(); poem.add("感時花濺淚"); poem.add("恨別鳥驚心"); // 直接將多個字符串內容寫入指定文件中 Files.write(Paths.get("pome.txt"), poem, Charset.forName("gbk")); // 使用Java 8新增的Stream API列出當前目錄下所有文件和子目錄 Files.list(Paths.get(".")).forEach(path -> System.out.println(path)); // 使用Java 8新增的Stream API讀取文件內容 Files.lines(Paths.get("FilesTest.java"), Charset.forName("gbk")).forEach(line -> System.out.println(line)); FileStore cStore = Files.getFileStore(Paths.get("C:")); // 判斷C盤的總空間,可用空間 System.out.println("C:共有空間:" + cStore.getTotalSpace()); System.out.println("C:可用空間:" + cStore.getUsableSpace()); } }
Files類提供了兩個方法來遍歷文件和子目錄
walkFileTree(Path start, FileVisitor super Path> visitor):遍歷start路徑下的所有文件和子目錄
walkFileTree(Path start, Set
FileVisitor代表一個文件訪問器,walkFileTree()方法會自動遍歷start路徑下的所有文件和子目錄,遍歷文件和子目錄都會觸發FileVisitor中相應的方法。這四個方法在下面的代碼中出現。FileVisitor中定義了如下4個方法:
FileVisitResult postVisitDirectory(T dir, IOException exc):訪問子目錄之后觸發該方法
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs):訪問子目錄之前觸發該方法
FileVisitResult visitFile(T file, BasicFileAttributes attrs):訪問file文件時觸發該方法
FileVisitResult visitFileFailed(T file, IOException exc):訪問file文件失敗時觸發該方法
FileVisitResult對象,它是一個枚舉類,代表訪問之后的后續行為,它有如下幾種后續行為:
CONTINUE:代表“繼續訪問”的后續行為
TERMINATE:代表“終止訪問”的后續行為
SKIP_SUBTREE:代表“繼續訪問“,但不訪問該目錄文件或目錄的子目錄樹
SKIP_SIBLINGS:代表“繼續訪問”,但不訪問該文件或目錄的兄弟文件或目錄
以下程序使用Files工具類的walkFileTree()方法遍歷g:publishcodes15目錄下的所有文件和子目錄,直到找到的文件以“FileVisitorTest.java”結尾,則程序停止遍歷。實現了對指定目錄進行搜索,直到找到指定文件為止
import java.io.*; import java.nio.file.*; import java.nio.file.attribute.*; public class FileVisitorTest { public static void main(String[] args) throws Exception { // 遍歷D:codingJava路徑CrazyJavacodes15目錄下的所有文件和子目錄 Files.walkFileTree(Paths.get("D:", "coding", "Java路徑", "CrazyJava", "codes", "15"), new SimpleFileVisitor使用WatchService監控文件變化() { // 訪問文件時候觸發該方法 @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println("正在訪問" + file + "文件"); // 找到了FileVisitorTest.java文件 if (file.endsWith("FileVisitorTest.java")) { System.out.println("--已經找到目標文件--"); return FileVisitResult.TERMINATE; } return FileVisitResult.CONTINUE; } // 開始訪問目錄時觸發該方法 @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { System.out.println("正在訪問:" + dir + " 路徑"); return FileVisitResult.CONTINUE; } }); } }
register(WatchService watcher, WatchEvent.Kind> ... events):用watcher監聽該path代表的目錄下文件變化。events參數指定要監聽哪些類型的事件
WatchService代表一個文件系統監聽服務,它負責監聽path代表的目錄下的文件變化。一旦使用register()方法完成注冊之后,可調用WatchService如下的三個方法來監聽目錄的文件變化事件
WatchKey poll():獲取下一個WatchKey,如果沒有WatchKey發生就立即返回null
WatcheKey poll(long timeout, TimeUnit unit):嘗試等待timeout時間去獲取下一個WatchKey
WatchKey take():獲取下一個WatchKey,如果沒有WatchKey發生就一直等待
如果程序需要一直監控,則應該選擇使用take()方法,如果程序只需要監控指定時間,則使用poll方法
import java.io.*; import java.nio.file.*; import java.nio.file.attribute.*; public class WatchServiceTest { public static void main(String[] args) throws Exception { // 獲取文件系統的WatchService對象 WatchService watchService = FileSystems.getDefault().newWatchService(); // 為C:盤根路徑注冊監聽 Paths.get("C:/").register(watchService , StandardWatchEventKinds.ENTRY_CREATE , StandardWatchEventKinds.ENTRY_MODIFY , StandardWatchEventKinds.ENTRY_DELETE); while(true) { // 獲取下一個文件改動事件 WatchKey key = watchService.take(); //① for (WatchEvent> event : key.pollEvents()) { System.out.println(event.context() +" 文件發生了 " + event.kind()+ "事件!"); } // 重設WatchKey boolean valid = key.reset(); // 如果重設失敗,退出監聽 if (!valid) { break; } } } }訪問文件屬性
Java7的NIO.2在java.nio.file.attribute包下提供了大量工具類,可以簡單地讀取、修改文件屬性。分為如下兩類:
XxxAttributeView:代表某種文件屬性的“視圖”
XxxAttributes:代表某種文件屬性的“集合”,程序一般通過XxxAttributeView對象獲取XxxAttributes
FileAttributeView是其他XxxAttributeView的父接口
AclFileAttributeView: 為特定文件設置ACL(Access Control List)及文件所有者屬性。getAcl()方法返回List
BaseFileAttributeView:獲取或修改文件的基本屬性。readAttributes()方法返回一個BaseFileAttributeView對象,對文件夾基本屬性的修改是通過BaseFileAttributeView對象完成的
DosFileAttributeView:獲取或修改文件DOS相關屬性。readAttributes()方法返回一個DosFileAttributeView對象,對文件夾屬性的修改通過DosFileAttributeView對象完成的
FileOwnerAttributeView:獲取或修改文件的所有者。getOwner()方法返回一個UserPrincipal對象來代表文件所有者;也可調用setOwner(UserPrincipal owner)方法來改變文件的所有者
PosixFileAttributeView:獲取文件或修改POSIX(Portable Operating System Interface of INIX)屬性。readAttributes()方法返回一個PosixFileAttributeView對象,該對象用于獲取或修改文件的所有者、組所有者、訪問權限信息。僅在UNIX、Linux等系統上有用
UserDefinedFileAttributeView:開發者自定義文件屬性
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66608.html
摘要:異步可以讓你異步的使用,例如當線程從通道讀取數據到緩沖區時,線程還是可以進行其他事情。當數據被寫入到緩沖區時,線程可以繼續處理它。因此,單個的線程可以監聽多個數據通道。下面是系列文章的目錄概述通道之間的數據傳輸與原文譯者郭蕾校對方騰飛 Java NIO(New IO)是一個可以替代標準Java IO API的IO API(從Java 1.4開始),Java NIO提供了與標準IO不同的...
摘要:線程之間的切換對于操作系統來說是昂貴的。因此,單線程可以監視多個通道中的數據。當方法返回后,線程可以處理這些事件。 一 NIO簡介 Java NIO 是 java 1.4 之后新出的一套IO接口,這里的的新是相對于原有標準的Java IO和Java Networking接口。NIO提供了一種完全不同的操作方式。 NIO中的N可以理解為Non-blocking,不單純是New。 它支持面...
摘要:從通道進行數據寫入創建一個緩沖區,填充數據,并要求通道寫入數據。三之通道主要內容通道介紹通常來說中的所有都是從通道開始的。從中選擇選擇器維護注冊過的通道的集合,并且這種注冊關系都被封裝在當中停止選擇的方法方法和方法。 由于內容比較多,我下面放的一部分是我更新在我的微信公眾號上的鏈接,微信排版比較好看,更加利于閱讀。每一篇文章下面我都把文章的主要內容給列出來了,便于大家學習與回顧。 Ja...
摘要:簡介是由引進的異步由以下幾個核心部分組成和的對比和的區別主要體現在三個方面基于流而基于操作是阻塞的而操作是非阻塞的沒有概念而有概念基于與基于傳統的是面向字節流或字符流的而在中我們拋棄了傳統的流而是引入了和的概念在中我只能從中讀取數據到中或將 簡介 Java NIO 是由 Java 1.4 引進的異步 IO.Java NIO 由以下幾個核心部分組成: Channel Buffer Se...
摘要:學習和掌握技術已經不是一個攻城獅的加分技能,而是一個必備技能。是雙向的,不僅可以讀取數據還能保存數據,程序不能直接讀寫通道,只與緩沖區交互為了讓大家不被高并發與大量連接處理問題所困擾,動力節點推出了高效處理模型應用教程。 大家肯定了解Java IO, 但是對于NIO一般是陌生的,而現在使用到NIO的場景越來越多,很多技術框...
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問題是阻塞,同步。每次請求都由程序執行并返回,這是同步的缺陷。這些都會被注冊在多路復用器上。多路復用器提供選擇已經就緒狀態任務的能力。并沒有采用的多路復用器,而是使用異步通道的概念。 Netty是一個提供異步事件驅動的網絡應用框架,用以快速開發高性能、高可靠的網絡服務器和客戶端程序。Netty簡化了網絡程序的開發,是很多框架和公司...
閱讀 1058·2021-11-12 10:34
閱讀 985·2021-09-30 09:56
閱讀 668·2019-08-30 15:54
閱讀 2602·2019-08-30 11:14
閱讀 1465·2019-08-29 16:44
閱讀 3203·2019-08-29 16:35
閱讀 2489·2019-08-29 16:22
閱讀 2441·2019-08-29 15:39