1、兩種獲取通道的方法
FileChannel.open()的方式
FileChannel channell = FileChannel.open(Paths.get("a.txt","c.txt"), StandardOpenOption.CREATE,StandardOpenOption.WRITE); FileChannel channel2 = FileChannel.open(new File("a.txt").toPath(), StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE,StandardOpenOption.READ);
path獲取
Paths.get() new File(“a.txt”).toPath()
OpenOption接口的實現類通常由StandardOpenOption枚舉進行代替。
public enum StandardOpenOption implements OpenOption { READ, WRITE, APPEND,//累加 TRUNCATE_EXISTING,//如果該文件已存在並且為寫入訪問而打開,則其長度將被截斷為0。如果只為讀取訪問打開文件,則忽略此選項。 CREATE,//不能單獨使用,要與WRITE配套使用,單獨使用會報錯java.nio.file.NoSuchFileException,如果文件已存在,重復創建不會報錯 CREATE_NEW,//不能單獨使用,要與WRITE配套使用,如果文件已存在,則出現異常java.nio.file.FileAlreadyExistsException DELETE_ON_CLOSE, SPARSE,//稀疏文件,空閑位置不占內存(不要使用CREATE來創建稀疏文件) SYNC,//要求對文件內容或元數據的每次更新都同步寫入底層存儲設備。如果這樣做,程序運行的效率就降低了。 DSYNC;//要求對文件內容的每次更新都同步寫入底層存儲設備。 //枚舉常量SYNC與DSYNC的區別:SYNC更新內容與元數據,而DSYNC只更新內容,與force(boolean)方法作用一樣。
從io流中獲得通道getChannel()
FileChannel inchannel = new FileInputStream("a.txt").getChannel(); FileChannel outchannel = new FileOutputStream("b.txt").getChannel(); FileChannel inchannel1 = new RandomAccessFile("a.txt","r").getChannel(); FileChannel outchannel1 = new RandomAccessFile("a.txt","rw").getChannel();
2、read
ByteBuffer buffer = ByteBuffer.allocate(10); ByteBuffer buffer1 = ByteBuffer.allocate(10); ByteBuffer[] buffers = {buffer,buffer1}; channel2.read(buffer);//將字節序列從此通道的當前位置讀入給定的緩沖區的當前位置,方法同步,返回值正數為讀取的字節數,0為未讀取到數據,可能是緩沖區中沒有剩余空間了,-1是到了流的末端 channel2.read(buffer,2);//position代表通道的位置 channel2.read(buffers);//將通道當前位置的字節序列讀入多個ByteBuffer緩沖區的remaining剩余空間中,方法同步 channel2.read(buffers,0,8);//offset代表數組的下表,length為向后的緩沖區個數
3、write
ByteBuffer buffer2 = ByteBuffer.wrap(new byte[]{1,2,3,4}); ByteBuffer buffer3 = ByteBuffer.wrap(new byte[]{11,21,31,41}); ByteBuffer[] buffers1 = {buffer2,buffer3}; channell.write(buffer2);//將一個緩沖區中remaining字節序列寫入通道的當前位置,write方法同步 channell.write(buffer2,2);//將一個緩沖區中remaining字節序列寫入通道的指定位置,此方法不改變痛的位置,write方法同步 channell.write(buffers);//將多個緩沖區中的remaining剩余字節序列寫入通道的當前位置,方法同步 channell.write(buffers1,0,8);//指定緩沖區數組的offset下表開始,向后length個字節緩沖區,將每個緩沖區的remaining剩余字節序列寫入此通道的當前位置
4、獲取和設置通道的位置、大小
channell.position(); channell.position(2); channell.size();//此通道關聯文件的當前大小
5、long transferTo(position,count,WritableByteChannel dest)
1)position:文件中的位置,從此位置開始傳輸,必須為非負數。
2)count:要傳輸的最大字節數;必須為非負數。
3)dest:目標通道。
long transferTo(position,count,WritableByteChannel dest)方法的作用是將字節從此通道的文件傳輸到給定的可寫入字節通道。
1、試圖讀取從此通道的文件中給定position處開始的count個字節,並將其寫入目標通道的當前位置。
2、此方法的調用不一定傳輸所有請求的字節,是否傳輸取決於通道的性質和狀態。
如果此通道的文件從給定的position處開始所包含的字節數小於count個字節,或者如果目標通道是非阻塞的並且其輸出緩沖區中的自由空間少於count個字節,則所傳輸的字節數要小於請求的字節數。
3、此方法不修改此通道的位置。如果給定的位置大於該文件的當前大小,則不傳輸任何字節,否則從目標通道的position位置起始開始寫入各字節,然后將該位置增加寫入的字節數。
4、與從此通道讀取並將內容寫入目標通道的簡單循環語句相比,此方法可能高效得多。很多操作系統可將字節直接從文件系統緩存傳輸到目標通道,而無須實際復制各字節。
6、long transferFrom(ReadableByteChannel src,position,count)
1)src:源通道。
2)position:文件中的位置,從此位置開始傳輸;必須為非負數。
3)count:要傳輸的最大字節數;必須為非負數。
注意,參數position是指當前通道的位置,而不是指src源通道的位置。參數position針對於調用transferTo()或transferFrom()方法的對象。
long transferFrom(ReadableByteChannel src,position,count)方法的作用是將字節從給定的可讀取字節通道傳輸到此通道的文件中。
1、試着從源通道中最多讀取count個字節,並將其寫入到此通道的文件中從給定position處開始的位置。
2、此方法的調用不一定傳輸所有請求的字節;是否傳輸取決於通道的性質和狀態。
如果源通道的剩余空間小於count個字節,或者如果源通道是非阻塞的並且其輸入緩沖區中直接可用的空間小於count個字節,則所傳輸的字節數要小於請求的字節數。
3、此方法不修改此通道的位置。如果給定的位置大於該文件的當前大小,則不傳輸任何字節。從源通道中的當前位置開始讀取各字節寫入到當前通道,然后將src通道的位置增加讀取的字節數。
4、與從源通道讀取並將內容寫入此通道的簡單循環語句相比,此方法可能高效得多。很多操作系統可將字節直接從源通道傳輸到文件系統緩存,而無須實際復制各字節。
7、截斷緩沖區(在源文件上截取,並不是得到新文件)
channel2.truncate(100);
truncate(long size)方法的作用是將此通道的文件截取為給定大小。
如果給定大小小於該文件的當前大小,則截取該文件,丟棄文件新末尾后面的所有字節。
如果給定大小大於或等於該文件的當前大小,則不修改文件。
無論是哪種情況,如果此通道的文件位置大於給定大小,則將位置設置為該大小。
8、將通道文件區域直接映射到內存 map()
MappedByteBuffer map(FileChannel.MapMode mode,long position,long size)方法的作用是將此通道的文件區域直接映射到內存中。
1)mode:根據只讀、讀取/寫入或專用(寫入時復制)來映射文件,分別為FileChannel.MapMode類中所定義的READ_ONLY、READ_WRITE和PRIVATE;
2)position:文件中的位置,映射區域從此位置開始;必須為非負數。
3)size:要映射的區域大小;必須為非負數且不大於Integer.MAX_VALUE。
可以通過下列3種模式將文件區域映射到內存中。
1)只讀:試圖修改得到的緩沖區將導致拋出ReadOnlyBufferException異常。(MapMode.READ_ONLY)
2)讀取/寫入:對得到的緩沖區的更改最終將傳播到文件;該更改對映射到同一文件的其他程序不一定是可見的。(MapMode.READ_WRITE)
3)專用:對得到的緩沖區的更改不會傳播到文件,並且該更改對映射到同一文件的其他程序也不是可見的;相反,會創建緩沖區已修改部分的專用副本。(MapMode.PRIVATE)
總結:
1、對於只讀映射關系,此通道必須可以進行讀取操作;對於讀取/寫入或專用映射關系,此通道必須可以進行讀取和寫入操作。
2、此方法返回的已映射字節緩沖區位置為零,限制和容量為size;其標記是不確定的。在緩沖區本身被作為垃圾回收之前,該緩沖區及其表示的映射關系都是有效的。
3、映射關系一經創建,就不再依賴於創建它時所用的文件通道。特別是關閉該通道對映射關系的有效性沒有任何影響。
4、對於大多數操作系統而言,與通過普通的read()和write()方法讀取或寫入數千字節的數據相比,將文件映射到內存中開銷更大。從性能的觀點來看,通常將相對較大的文件映射到內存中才是值得的。
MappedByteBuffer的簡單介紹:
它是直接字節緩沖區,其內容是文件的內存映射區域。映射的字節緩沖區是通過FileChannel.map()方法創建的。此類用特定於內存映射文件區域的操作擴展ByteBuffer類。
public abstract class MappedByteBuffer extends ByteBuffer
作為ByteBuffer的子類,除了具有父類的方法外,還新增了
force()將此緩沖區所做的內容更改強制寫入包含映射文件的存儲設備中。
load()將此緩沖區內容加載到物理內存中。
isLoaded()判斷次緩沖區的內容是否位於物理內存中。
FileChannel類或MappedByteBuffer類對文件進行操作時,在大部分情況下,它們的效率並不比使用InputStream或OutputStream高很多,這是因為NIO的出現是為了解決操作I/O線程阻塞的問題,使用NIO就把線程變成了非阻塞,這樣就提高了運行效率。
NIO真正的優勢:非阻塞。