JNI 探秘 — FileInputStream 的 read 方法详解

栏目: Java · 发布时间: 7年前

内容简介:JNI 探秘 — FileInputStream 的 read 方法详解

上一章我们已经分析过FileInputStream的构建过程,接下来我们就来看一下read方法的读取过程。

我们先来看下FileInputStream中的四个有关read的方法的源码,如下。

public native int read() throws IOException;

    private native int readBytes(byte b[], int off, int len) throws IOException;

    public int read(byte b[]) throws IOException {
    return readBytes(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
    return readBytes(b, off, len);
    }

可以看到,其中有两个本地方法,两个不是本地方法,但是还是内部还是调用的本地方法,那么我们研究的重点就是这两个本地方法到底是如何实现的。

下面是这两个本地方法的源码,非常简单,各位请看。

JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_read(JNIEnv *env, jobject this) {
    return readSingle(env, this, fis_fd);//每一个本地的实例方法默认的两个参数,JNI环境与对象的实例
}

JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_readBytes(JNIEnv *env, jobject this,
        jbyteArray bytes, jint off, jint len) {//除了前两个参数,后三个就是readBytes方法传递进来的,字节数组、起始位置、长度三个参数
    return readBytes(env, this, bytes, off, len, fis_fd);
}

可以看到,这两个本地方法的实现只是将任务又转给了两个方法,readSingle和ReadBytes,请注意,在调用这两个方法时,除了常用的env和this对象,以及从 JAVA 环境传过来的参数之外,还多了一个参数fis_fd,这个对象就是上一章中FileInputStream类中的fd属性的地址偏移量了。

那么下面我们首先来看readSingle方法的实现,如下。

/*
    env和this参数就不再解释了
    fid就是FileInputStream类中fd属性的地址偏移量
    通过fid和this实例可以获取FileInputStream类中fd属性的内存地址
*/
jint
readSingle(JNIEnv *env, jobject this, jfieldID fid) {
    jint nread;//存储读取后返回的结果值
    char ret;//存储读取出来的字符
    FD fd = GET_FD(this, fid);//这个获取到的FD其实就是之前handle属性的值,也就是文件的句柄
    if (fd == -1) {
        JNU_ThrowIOException(env, "Stream Closed");
        return -1;//如果文件句柄等于-1,说明文件流已关闭
    }
    nread = (jint)IO_Read(fd, &ret, 1);//读取一个字符,并且赋给ret变量
    //以下根据返回的int值判断读取的结果
    if (nread == 0) { /* EOF */
        return -1;//代表流已到末尾,返回-1
    } else if (nread == JVM_IO_ERR) { /* error */
        JNU_ThrowIOExceptionWithLastError(env, "Read error");//IO错误
    } else if (nread == JVM_IO_INTR) {
        JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);//被打断
    }
    return ret & 0xFF;//与0xFF做按位的与运算,去除高于8位bit的位
}

可以看到,这个方法其实最关键的就是IO_Read这个宏定义的处理,而IO_Read其实只是代表了一个方法名称叫handleRead,我们去看一下handleRead的源码。

/*
    fd就是handle属性的值
    buf是收取读取内容的数组
    len是读取的长度,可以看到,这个参数传进来的是1
    函数返回的值代表的是实际读取的字符长度
*/
JNIEXPORT
size_t
handleRead(jlong fd, void *buf, jint len)
{
    DWORD read = 0;
    BOOL result = 0;
    HANDLE h = (HANDLE)fd;
    if (h == INVALID_HANDLE_VALUE) {//如果句柄是无效的,则返回-1
        return -1;
    }
    //这里ReadFile又是一个现有的函数,和上一章的CreateFile是一样的
    //都是WIN API的函数,可以百度搜索它的作用与参数详解,理解它并不难
    result = ReadFile(h,          /* File handle to read */  //文件句柄
                      buf,        /* address to put data */  //存放数据的地址
                      len,        /* number of bytes to read */  //要读取的长度
                      &read,      /* number of bytes read */  //实际读取的长度
                      NULL);      /* no overlapped struct */  //只有对文件进行重叠操作时才需要传值
    if (result == 0) {//如果没读取出来东西,则判断是到了文件末尾返回0,还是报错了返回-1
        int error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            return 0; /* EOF */
        }
        return -1;
    }
    return read;
}

到此,基本上就完全看完了无参数的read方法的源码,它的原理其实很简单,就是利用handle这个句柄,使用ReadFile的WIN API函数读取了一个字符,不过值得注意的是,这些都是windows系统下的实现方式,所以不可认为这些源码代表了所有系统下的情况。

然而对于带有参数的read方法,其原理与无参read方法是一样的,而且最终也是调用的handleRead这个方法,只是读取的长度不再是1而已。

由此可以看出,文件输入流只是已只读方式打开了一个文件流,而且这个文件流只能依次向后读取,因为在之前的 设计模式 系列装饰器模式一文中,LZ已经提到过,对于FileInputStream进行包装而支持回退,标记重置等操作的输入流,都只是在内存里创建缓冲区造成的假象,我们真正的文件输入流是不支持这些操作的。

好了,有关FileInputstream的源码内容就分享到此了,如果有兴趣的猿友,可以继续看一下其它的本地方法是如何实现的。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Measure What Matters

Measure What Matters

John Doerr / Portfolio / 2018-4-24 / GBP 19.67

In the fall of 1999, John Doerr met with the founders of a start-up he’d just given $11.8 million, the biggest investment of his career. Larry Page and Sergey Brin had amazing technology, entrepreneur......一起来看看 《Measure What Matters》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试