java從jdk1.4后就引入了java NIO機制:
NIO的顯著特點就是通道(channel)、緩沖(buffer)、選擇器(selector),NIO機制中添加了傳統I/O機制中沒有的非阻塞調用(這對于網絡通信很有用,可以有效利用CPU),但是這個只能對于網絡通道(Socketchannel)才適用,filechannel還是阻塞調用。
我們現在專門分析的是java中的文件I/O機制,而不管網絡的socket通信機制。
Java中傳統的文件系統I/O機制是Filesystem和File,java中的Filesystem是java中的內部類,不提供對外的顯示特性,File類中的包含了Filesystem的對象,從而對于File的操作,比如rename、create etc 都轉成成java中的內部類Filesystem的操作。下面的是java中的Filesystem的抽象類:
abstract class FileSystem { /** * Return the FileSystem object rePResenting this platform's local * filesystem. */ public static native FileSystem getFileSystem(); /* -- Normalization and construction -- */ /** * Return the local filesystem's name-separator character. */ public abstract char getSeparator(); /** * Return the local filesystem's path-separator character. */ public abstract char getPathSeparator(); 。。。。。。
}
每個操作系統中都有一個具體的文件系統,而在windows下,通過Filesystem的getFilesystem()操作獲取本地文件系統,win32Filesystem; 而對于linux系統下,獲取的是unixFilesystem;
而java中傳統的I/O機制中的File對象,通過包含Filesystem對象,來達到對于文件系統下文件的管理操作create、delete、rename等。而關于文件的I/O數據流,輸入和輸出,采用的是Fileinputstream和Fileoutputstream。下面以Fileinputstream為例,Fileinputstream中的文件操作函數包括如下:
private native void open(String name) throws FileNotFoundException;
/** * Reads a byte of data from this input stream. This method blocks * if no input is yet available. * * @return the next byte of data, or <code>-1</code> if the end of the * file is reached. * @exception IOException if an I/O error occurs. */ public int read() throws IOException { Object traceContext = IoTrace.fileReadBegin(path); int b = 0; try { b = read0(); } finally { IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1); } return b; } private native int read0() throws IOException;
/** * Reads a subarray as a sequence of bytes. * @param b the data to be written * @param off the start offset in the data * @param len the number of bytes that are written * @exception IOException If an I/O error has occurred. */ private native int readBytes(byte b[], int off, int len) throws IOException; public native long skip(long n) throws IOException;
等,上面是幾個重要的函數,每次File讀取操作的時候都有個文件讀取位置,在linux文件系統下是文件描述符FileDescriptor,而windows系統下是handler,讀取位置是通過FileDescriptor或者Handler來完成的,每次只能從上一次的位置讀取文件操作。
但是Java中的NIO(New I/O)中引入了FileChannel,在FileChannel中有如下新特性:
相應的Filechannel是一個抽象類:
public abstract class FileChannel extends AbstractInterruptibleChannel implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel {。。。}
新增加的方法是: /** * Reads a sequence of bytes from this channel into the given buffer, * starting at the given file position. * * <p> This method works in the same manner as the {@link * #read(ByteBuffer)} method, except that bytes are read starting at the * given file position rather than at the channel's current position. This * method does not modify this channel's position. If the given position * is greater than the file's current size then no bytes are read. </p> public abstract int read(ByteBuffer dst, long position) throws IOException; /** * Writes a sequence of bytes to this channel from the given buffer, * starting at the given file position. * * <p> This method works in the same manner as the {@link * #write(ByteBuffer)} method, except that bytes are written starting at * the given file position rather than at the channel's current position. * This method does not modify this channel's position. If the given * position is greater than the file's current size then the file will be * grown to accommodate the new bytes; the values of any bytes between the * previous end-of-file and the newly-written bytes are unspecified. </p> public abstract int write(ByteBuffer src, long position) throws IOException; /** * Acquires a lock on the given region of this channel's file. public abstract FileLock lock(long position, long size, boolean shared) throws IOException; /** * Forces any updates to this channel's file to be written to the storage * device that contains it. public abstract void force(boolean metaData) throws IOException; /** * Transfers bytes from this channel's file to the given writable byte * channel. * <p> This method is potentially much more efficient than a simple loop * that reads from this channel and writes to the target channel. Many * Operating systems can transfer bytes directly from the filesystem cache * to the target channel without actually copying them. </p> public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException; 上述是FileChannel新增的方法。
傳統的Java中的I/O機制中的FileInputStream的成員變量:
private final FileDescriptor fd; 即傳統的java文件系統采用的是通過文件描述符的形式來記住文件的存取位置
而java中的NIO機制也是采用類似的機制:
// Used to make native read and write calls private static NativeDispatcher nd; // Memory allocation size for mapping buffers private static long allocationGranularity; // Cached field for MappedByteBuffer.isAMappedBuffer private static Field isAMappedBufferField; // File descriptor private FileDescriptor fd; 上面是一個具體的Filechannel類,FilechannelImpl部分成員變量。
新聞熱點
疑難解答