关于Android中的文件读写(jniGetFDFromFileDescriptor)
来源:互联网 发布:淘宝导购返现网 编辑:程序博客网 时间:2024/06/05 09:35
转自: http://blog.chinaunix.net/uid-26926660-id-3326678.html
关键字:jniGetFDFromFileDescriptor
1.分析
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();
2.实现
开门见山,总的流程图如下:
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设计得完全不同的类,但其底层实现还是一样的。
3.总结
至此,Java的文件读写调用最终转换成UNIX系统调用,并且Android java中的flush函数是个空的函数,从整个过程来看,FileInputStream/FileOutputStream、RandomAccessFile并没有使用任何的缓冲机制,且其调用过程也比较简单明了。
- 关于Android中的文件读写(jniGetFDFromFileDescriptor)
- 关于Android中的文件读写
- Android中的文件读写
- 关于java中的读写文件
- Android中的文件读写操作
- 关于java中的文件读写操作
- (转)关于文件读写
- Android关于文件读写方面整理
- Android 中关于文件的读写操作
- Android中的多种文件读写操作方法
- Android中的多种文件读写操作方法
- Android中的多种文件读写操作方法
- Android中的多种文件读写操作方法
- Android中的多种文件读写操作方法
- Android开发中的文件的读写
- Android中的多种文件读写操作方法
- Android中的多种文件读写操作方法
- Android中的文件读写全面总结
- TreeView 图标不能显示问题
- c++ vector 排序
- java 内存溢出 及时解决办法
- 生成java可执行文件(bat)
- jsp中文传参乱码问题
- 关于Android中的文件读写(jniGetFDFromFileDescriptor)
- 在Oracle 10g中建立没有域名的DB_LINK
- 卓普大黑网站样式表文件分享
- Android的全局键(home键/长按耳机键)详解【android源码解析八】
- struts2 iterator 限制 输出
- Unable to resolve target 'android-i'
- 获取文件大小的几种方法
- JAVA-设计模式之门面模式
- Visual Studio 2010 中遇到了异常