NIO:New IOjava
新IO採用內存映射文件的方式來處理輸入/輸出,新IO文件或文件的一段區域映射到內存中,這樣就能夠訪問內存同樣來訪問文件了(這種方式模擬了操做系統上的虛擬內存的概念),經過這種方式來進行輸入/輸出比傳統的輸入/輸出要快得多數組
Java中NIO相關的包以下:併發
java.nio包:主要提供了一些和Buffer相關的類app
java.nio.channels包:主要包括Channel和Selector相關的類dom
java.nio.charset包:主要包含和字符集相關的類eclipse
java.nio.channels.spi包:主要包含提供Channel服務的類異步
java.nio.charset.spi包:主要包含提供字符集服務的相關類ide
Channel(通道)和Buffer(緩衝)是新IO中的兩個核心對象,Channel是對傳統輸入/輸出系統中的模擬,在新IO系統中全部數據都須要經過通道傳輸;Channel與傳統的InputStream、OutputStream最大的區別在於它提供了一個map方法,經過該map方法能夠直接將「一塊數據」映射到內存中。若是說傳統的輸入/輸出系統是面向流的處理,而新IO則是面向塊的處理工具
Buffer能夠被理解成一個容器,它的本質是一個數組,發送到Channel中的全部對象都必須首先放到Buffer中,而從Channel中讀取的數據也必須先讀到Buffer中。此處的Buffer有點相似於前面咱們介紹的「竹筒」,但該Buffer既能夠像前面那樣一次、一次去Channel中取水,也容許使用Channel直接將文件的某塊數據映射成Bufferpost
除了Channel和Buffer以外,新IO還提供了用於將UNICODE字符串映射成字節序列以及逆映射操做的Charset類,還提供了用於支持非阻塞式輸入/輸出的Selector類
Buffer類沒有提供構造器,經過使用以下方法來獲得一個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
Channel相似於傳統的流對象,但與傳統的流對象有兩個主要區別:
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,爲下一次讀取數據作準備
編碼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支持的所有字符集 SortedMap<String,Charset> map = 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("\n" + 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(); } } }
NIO的改進主要包括以下方面:
提供了全面的文件IO和文件系統訪問支持
基於異步Channel的IO
Paths提供了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:\Development\eclipse\workspace\CrazyJava\. absolutePath的根路徑:D:\ absolutePath裏包含的路徑數量:5 CrazyJava D:\java\code
如下代碼示範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<String> 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<String> 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<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor):遍歷start路徑下的全部文件和子目錄,最多遍歷maxDepth深度的文件
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:\coding\Java路徑\CrazyJava\codes\15目錄下的全部文件和子目錄 Files.walkFileTree(Paths.get("D:", "coding", "Java路徑", "CrazyJava", "codes", "15"), new SimpleFileVisitor<Path>() { // 訪問文件時候觸發該方法 @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<AclEntry>對象,該返回值表明該文件的權限集,setAcl(List)方法修改該文件的ACL
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:開發者自定義文件屬性