未公开的mustang核心秘密(三):jdk读取文件的秘密

   最近做一个很简单的函数,要两个返回值,我打算有一个类封装一下返回,后来领导要求使用StringBuilder返回,不用 StringBuffer,因为局部变量StringBuffer最后还是要编译为StringBuilder,因为StringBuilder没有任何 同步。
问了一下大家的看法,风南说InputStream 的int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中,也是类似的,看来有必要研究一下IO了。
 InputStream类中重要的函数,只有一个抽象的有用,
   public abstract int read() throws IOException;
其他两个read的意义不大。
 public int read(byte b[], int off, int len) throws IOException 和
 public int read(byte b[]) throws IOException {
    return read(b, 0, b.length);
    }
下面看它的子类FileInputStream的实现,
 /* File Descriptor - handle to the open file */
    private FileDescriptor fd;
这个很重要,这是文件句柄,C语言使用fopen函数的都知道。
/**
     * Opens the specified file for reading.
     * @param name the name of the file
     */
    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 native int read() 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;
子类修改了父的实现
    /**
     * Reads up to <code>b.length</code> bytes of data from this input
     * stream into an array of bytes. This method blocks until some input
     * is available.
     *
     * @param      b   the buffer into which the data is read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the file has been reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read(byte b[]) throws IOException {
    return readBytes(b, 0, b.length);
    }

    /**
     * Reads up to <code>len</code> bytes of data from this input stream
     * into an array of bytes. If <code>len</code> is not zero, the method
     * blocks until some input is available; otherwise, no
     * bytes are read and <code>0</code> is returned.
     *
     * @param      b     the buffer into which the data is read.
     * @param      off   the start offset in the destination array <code>b</code>
     * @param      len   the maximum number of bytes read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the file has been reached.
     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
     * <code>len</code> is negative, or <code>len</code> is greater than
     * <code>b.length - off</code>
     * @exception  IOException  if an I/O error occurs.
     */
    public int read(byte b[], int off, int len) throws IOException {
    return readBytes(b, off, len);
    }
看出readBytes是关键的所在,windows的native code中只有

JNIEXPORT void JNICALL
Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) {
    handleClose(env, this, fis_fd);
}
是平台相关的。
其他的在share中
FileInputStream.c代码
jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */

/**************************************************************
 * static methods to store field ID's in initializers
 */
得到fd的值,这个很重要
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass fdClass) {
    fis_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
}

/**************************************************************
 * Input stream
 */

JNIEXPORT void JNICALL
Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
    fileOpen(env, this, path, fis_fd, O_RDONLY);
}

JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_read(JNIEnv *env, jobject this) {
    return readSingle(env, this, fis_fd);
}

JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_readBytes(JNIEnv *env, jobject this,
    jbyteArray bytes, jint off, jint len) {
    return readBytes(env, this, bytes, off, len, fis_fd);
}

JNIEXPORT jlong JNICALL
Java_java_io_FileInputStream_skip(JNIEnv *env, jobject this, jlong toSkip) {
    jlong cur = jlong_zero;
    jlong end = jlong_zero;
    FD fd = GET_FD(this, fis_fd);
    if ((cur = IO_Lseek(fd, (jlong)0, (jint)SEEK_CUR)) == -1) {
        JNU_ThrowIOExceptionWithLastError(env, "Seek error");
    } else if ((end = IO_Lseek(fd, toSkip, (jint)SEEK_CUR)) == -1) {
    JNU_ThrowIOExceptionWithLastError(env, "Seek error");
    }
    return (end - cur);
}

JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_available(JNIEnv *env, jobject this) {
    jlong ret;
    FD fd = GET_FD(this, fis_fd);

    if (IO_Available(fd, &ret)) {
        if (ret > INT_MAX) {
        ret = (jlong) INT_MAX;
    }
    return jlong_to_jint(ret);
    }
    JNU_ThrowIOExceptionWithLastError(env, NULL);
    return 0;
}
主要是readBytes的实现,打开io_util.c文件
/* IO helper functions */

int
readSingle(JNIEnv *env, jobject this, jfieldID fid) {
    int nread;
    char ret;
    FD fd = GET_FD(this, fid);

    nread = IO_Read(fd, &ret, 1);
    if (nread == 0) { /* EOF */
    return -1;
    } else if (nread == JVM_IO_ERR) { /* error */
    JNU_ThrowIOExceptionWithLastError(env, "Read error");
    } else if (nread == JVM_IO_INTR) {
        JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
    }
    return ret & 0xFF;
}

/* The maximum size of a stack-allocated buffer.
 */
#define BUF_SIZE 8192


int
readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
      jint off, jint len, jfieldID fid)
{
    int nread, datalen;
    char stackBuf[BUF_SIZE];
    char *buf = 0;
    FD fd;

    if (IS_NULL(bytes)) {
    JNU_ThrowNullPointerException(env, 0);
    return -1;
    }
    datalen = (*env)->GetArrayLength(env, bytes);

    if ((off < 0) || (off > datalen) ||
        (len < 0) || ((off + len) > datalen) || ((off + len) < 0)) {
        JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0);
    return -1;
    }

    if (len == 0) {
    return 0;
    } else if (len > BUF_SIZE) {
        buf = malloc(len);
    if (buf == 0) {
        JNU_ThrowOutOfMemoryError(env, 0);
        return 0;
        }
    } else {
        buf = stackBuf;
    }

    fd = GET_FD(this, fid);
    nread = IO_Read(fd, buf, len);
    if (nread > 0) {
        (*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
    } else if (nread == JVM_IO_ERR) {
    JNU_ThrowIOExceptionWithLastError(env, "Read error");
    } else if (nread == JVM_IO_INTR) { /* EOF */
        JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
    } else { /* EOF */
    nread = -1;
    }

    if (buf != stackBuf) {
        free(buf);
    }
    return nread;
}
注意IO_Read在io_util_md.h做了手脚的,
#define IO_Read JVM_Read
其实就是JVM_Read,JVM_Read在hotspot源码中定义的
  //%note jvm_r6
  return (jint)hpi::read(fd, buf, nbytes);
hpi定义了大量的函数
  // HPI_FileInterface
  static inline char*  native_path(char *path);
  static inline int    file_type(const char *path);
  static inline int    open(const char *name, int mode, int perm);
  static inline int    close(int fd);
  static inline jlong  lseek(int fd, jlong off, int whence);
  static inline int    ftruncate(int fd, jlong length);
  static inline int    fsync(int fd);
  static inline int    available(int fd, jlong *bytes);
  static inline size_t read(int fd, void *buf, unsigned int nBytes);
  static inline size_t write(int fd, const void *buf, unsigned int nBytes);
  static inline int    fsize(int fd, jlong *size);
这就是和平台相关的代码了。window下通过HPIDECL宏转换的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值