分类: Java
2015-05-04 17:15:29
原文地址:关于Android中的文件读写 作者:铸道的汉子
Java中常用的文件读写的两个类:
1.FileInputStream/FileOutputStream(FileReader/FileWriter)
2.RandomFileAccess
FileInputSteam和FileOutputStream继承于InputStream和OutputStream,FileReader、FileWriter继承于Reader和Writer,它们的底层实现原理其实是样的,区别在于一个前者用于字节型数据流读写,后者用于unicode文本流读写
RandomFileAccess是一个独立的文件读写类,它与InputStream、OutputStream不同之处在于它更倾向与随机文件读写,类似C语言fopen、fread、fseek、fwrite、fflush、fclose的封装。
eg.FileOutputStream
File file2 = new File("FileOut.txt"); if(file2 == null) { dbgOutput("ERR","File 2 Can't make"); return; } FileOutputStream fos = new FileOutputStream(file2); //此处才会创建文件出来 if(fos == null) { dbgOutput("ERR","File 2 Output stream can't make"); return; } byte [] words = {'a','b','c','d','e'}; fos.write(words); fos.flush(); fos.close(); |
eg.RandomAccessFile
RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw"); for (int i = 0; i < 10; i++) { //写入基本类型double数据 rf.writeDouble(i * 1.414); } rf.close(); rf = new RandomAccessFile("rtest.dat", "rw"); //直接将文件指针移到第5个double数据后面 rf.seek(5 * 8); //覆盖第6个double数据 rf.writeDouble(47.0001); rf.close(); rf = new RandomAccessFile("rtest.dat", "r"); for (int i = 0; i < 10; i++) { System.out.println("Value " + i + ": " + rf.readDouble()); } rf.close(); |
Android Java 文件读写IO类的具体实现的代码在libcore中实现,原理也是通过JNI的方式实现的,对于
FileInputStream、FileOutStream类,继承于InputStream、OutputStream类,但InputStream、OutputStream只声明了抽象的read、write接口,如:
@ \libcore\luni\src\main\java\java\io\InputStream.java
@ \libcore\luni\src\main\java\java\io\OutputStream.java
public abstract int read() throws IOException; public abstract void write(int oneByte) throws IOException; |
具体的实现还是在FileInputStream、FileOutputStream中重写的,其中实现的代码如下:
@ \libcore\luni\src\main\java\java\io\FileInputStream.java
@ \libcore\luni\src\main\java\java\io\FileOutputStream.java
@Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { return IoBridge.read(fd, buffer, byteOffset, byteCount); } |
public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { IoBridge.write(fd, buffer, byteOffset, byteCount); } |
其中调用了IoBridge类实现,read、write方法都是静态方法,实现的代码如下:
@ \android\libcore\luni\src\main\java\libcore\io\IoBridge.java
read方法
/** * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional * Unix practice where you'd read until you got 0 bytes (and any future read would return -1). */ public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException { Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount); if (byteCount == 0) { return 0; } try { int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount); if (readCount == 0) { return -1; } return readCount; } catch (ErrnoException errnoException) { if (errnoException.errno == EAGAIN) { // We return 0 rather than throw if we try to read from an empty non-blocking pipe. return 0; } throw errnoException.rethrowAsIOException(); } } |
@ \android\libcore\luni\src\main\java\libcore\io\IoBridge.java
write方法:
/** * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike * Unix it never just writes as many bytes as happens to be convenient.) */ public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException { Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount); if (byteCount == 0) { return; } try { while (byteCount > 0) { int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount); byteCount -= bytesWritten; byteOffset += bytesWritten; } } catch (ErrnoException errnoException) { throw errnoException.rethrowAsIOException(); } } |
LibCore类只有Os这一个对象:
\libcore\luni\src\main\java\libcore\io\LibCore.java
package libcore.io;
public final class Libcore { private Libcore() { }
public static Os os = new BlockGuardOs(new Posix()); } |
Os对象是一系列系统调用的抽象接口,从LibCore.java中可以看出它是通过Posix这个类实现的,这个类中读写的实现如下:
@\libcore\luni\src\main\java\libcore\io\Posix.java
public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { if (buffer.isDirect()) { return readBytes(fd, buffer, buffer.position(), buffer.remaining()); } else { return readBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining()); } } public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { // This indirection isn't strictly necessary, but ensures that our public interface is type safe. return readBytes(fd, bytes, byteOffset, byteCount); } private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException; |
public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { if (buffer.isDirect()) { return writeBytes(fd, buffer, buffer.position(), buffer.remaining()); } else { return writeBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining()); } } public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { // This indirection isn't strictly necessary, but ensures that our public interface is type safe. return writeBytes(fd, bytes, byteOffset, byteCount); } private native int writeBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException; |
最终是通过native调用来实现的,
@\libcore\luni\src\main\native\libcore_io_Posix.cpp
static jint Posix_writeBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) { ScopedBytesRO bytes(env, javaBytes); if (bytes.get() == NULL) { return -1; } int fd = jniGetFDFromFileDescriptor(env, javaFd); return throwIfMinusOne(env, "write", TEMP_FAILURE_RETRY(write(fd, bytes.get() + byteOffset, byteCount))); } |
static jint Posix_readBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount) { ScopedBytesRW bytes(env, javaBytes); if (bytes.get() == NULL) { return -1; } int fd = jniGetFDFromFileDescriptor(env, javaFd); return throwIfMinusOne(env, "read", TEMP_FAILURE_RETRY(read(fd, bytes.get() + byteOffset, byteCount))); } |
对于RandomAccessFile的调用过程:
@\libcore\luni\src\main\java\java\io\RandomAccessFile.java
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { return IoBridge.read(fd, buffer, byteOffset, byteCount); } |
public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { IoBridge.write(fd, buffer, byteOffset, byteCount); // if we are in "rws" mode, attempt to sync file+metadata if (syncMetadata) { fd.sync(); } } |
虽然RandomAccessFile在java中是与FileInputStream、FileOutputStream设计得完全不同的类,但其底层实现还是一样的。
至此,Java的文件读写调用最终转换成UNIX系统调用,并且Android java中的flush函数是个空的函数,从整个过程来看,FileInputStream/FileOutputStream、RandomAccessFile并没有使用任何的缓冲机制,且其调用过程也比较简单明了。