博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java FileInputStream
阅读量:6711 次
发布时间:2019-06-25

本文共 5614 字,大约阅读时间需要 18 分钟。

hot3.png

 一、序言

        IO操作,才程序中比较普遍,JAVA 中提出了IO/NIO 的概念,也一直在说NIO 比IO快,一直不知道原因,就想memcache 和ehcache 比较优劣一样,这些东西得自己看看如何实现的,才 知道区别,从而才知道优劣以及试用范围,而不仅仅是“听说”!这里我可以先了解下JAVA 如何操作IO的。

 

二、代码示例

       我们先看看简单文件操作:

       

Java代码    
收藏代码
  1. // 这是将文件转换成输入流的的一种方式,获得了流我们就能干很多事  
  2. FileInputStream in = new FileInputStream(new File("...file"));  
 

 

       再看看FileInputStream 的源码:

    

Java代码    
收藏代码
  1. public FileInputStream(File file) throws FileNotFoundException {  
  2.     String name = (file != null ? file.getPath() : null);  
  3.         // 安全管理器,这里暂时不说  
  4.     SecurityManager security = System.getSecurityManager();  
  5.     if (security != null) {  
  6.             // 检查是否可以按这名字读取  
  7.         security.checkRead(name);  
  8.     }  
  9.         if (name == null) {  
  10.             throw new NullPointerException();  
  11.         }  
  12.         // 获得文件描述,这个JDK 未公布  
  13.     fd = new FileDescriptor();  
  14.         // 打开文件,这是个native 方法,我们可以用openjdk 看看里面  
  15.     open(name);  
  16.     }  
 

 

  在FileInputStream.c下可以找到方法

    

Java代码    
收藏代码
  1. // open 方法  
  2. JNIEXPORT void JNICALL  
  3. Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) {  
  4.     fileOpen(env, this, path, fis_fd, O_RDONLY);  
  5. }  
 

 

    OK。我们从该文件上面的引用io_util_md.c找到实现:

   

Java代码    
收藏代码
  1. void  
  2. fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)  
  3. {  
  4.     jlong h = winFileHandleOpen(env, path, flags);  
  5.     if (h >= 0) {  
  6.         // 设置fd 的值  
  7.         SET_FD(this, h, fid);  
  8.     }  
  9. }  
 

 

 

    在上面文件里面可以看到:winFileHandleOpen,

   

Java代码    
收藏代码
  1. jlong  
  2. winFileHandleOpen(JNIEnv *env, jstring path, int flags)  
  3. {  
  4.     const DWORD access =  
  5.         (flags & O_RDWR)   ? (GENERIC_WRITE | GENERIC_READ) :  
  6.         (flags & O_WRONLY) ?  GENERIC_WRITE :  
  7.         GENERIC_READ;  
  8.     const DWORD sharing =  
  9.         FILE_SHARE_READ | FILE_SHARE_WRITE;  
  10.     const DWORD disposition =  
  11.         /* Note: O_TRUNC overrides O_CREAT */  
  12.         (flags & O_TRUNC) ? CREATE_ALWAYS :  
  13.         (flags & O_CREAT) ? OPEN_ALWAYS   :  
  14.         OPEN_EXISTING;  
  15.     const DWORD  maybeWriteThrough =  
  16.         (flags & (O_SYNC | O_DSYNC)) ?  
  17.         FILE_FLAG_WRITE_THROUGH :  
  18.         FILE_ATTRIBUTE_NORMAL;  
  19.     const DWORD maybeDeleteOnClose =  
  20.         (flags & O_TEMPORARY) ?  
  21.         FILE_FLAG_DELETE_ON_CLOSE :  
  22.         FILE_ATTRIBUTE_NORMAL;  
  23.     const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;  
  24.     HANDLE h = NULL;  
  25.   
  26.     if (onNT) {  
  27.         WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);  
  28.         if (pathbuf == NULL) {  
  29.             /* Exception already pending */  
  30.             return -1;  
  31.         }  
  32.         h = CreateFileW(  
  33.             pathbuf,            /* Wide char path name */  
  34.             access,             /* Read and/or write permission */  
  35.             sharing,            /* File sharing flags */  
  36.             NULL,               /* Security attributes */  
  37.             disposition,        /* creation disposition */  
  38.             flagsAndAttributes, /* flags and attributes */  
  39.             NULL);  
  40.         free(pathbuf);  
  41.     } else {  
  42.         WITH_PLATFORM_STRING(env, path, _ps) {  
  43.             h = CreateFile(_ps, access, sharing, NULL, disposition,  
  44.                            flagsAndAttributes, NULL);  
  45.         } END_PLATFORM_STRING(env, _ps);  
  46.     }  
  47.     if (h == INVALID_HANDLE_VALUE) {  
  48.         int error = GetLastError();  
  49.         if (error == ERROR_TOO_MANY_OPEN_FILES) {  
  50.             JNU_ThrowByName(env, JNU_JAVAIOPKG "IOException",  
  51.                             "Too many open files");  
  52.             return -1;  
  53.         }  
  54.         throwFileNotFoundException(env, path);  
  55.         return -1;  
  56.     }  
  57.     return (jlong) h;  
  58. }  

 

   

 

  好吧,上面代码我也搞不明白- -,但是这几句代码:

  

Java代码    
收藏代码
  1.   h = CreateFileW(  
  2.             pathbuf,            /* Wide char path name */  
  3.             access,             /* Read and/or write permission */  
  4.             sharing,            /* File sharing flags */  
  5.             NULL,               /* Security attributes */  
  6.             disposition,        /* creation disposition */  
  7.             flagsAndAttributes, /* flags and attributes */  
  8.             NULL);  
  9.   
  10. 以及  
  11.    WITH_PLATFORM_STRING(env, path, _ps) {  
  12.             h = CreateFile(_ps, access, sharing, NULL, disposition,  
  13.                            flagsAndAttributes, NULL);    

 

   我的理解是,这里通过CreateFileW方法,创建了一个类似文件描述的结构,然后通过CreateFile调windows 下面的底层方法,填充这个结构的数据,那么这个文件对象就能被我们上层对象识别了,就能是获取里面的资源。

  OK,我们现在创建了对文件之间的连接,拿到文件流对象之后,来看看我们常用的read 方法。

   

Java代码    
收藏代码
  1. // 对字节的操作  
  2. public native int read() throws IOException;  
  3. private native int readBytes(byte b[], int off, int len) throws IOException;  

 

  

  在FileInputStream.c 里面同样可以找到

  

Java代码    
收藏代码
  1. JNIEXPORT jint JNICALL  
  2. Java_java_io_FileInputStream_read(JNIEnv *env, jobject this) {  
  3.     return readSingle(env, this, fis_fd);  
  4. }  
  5.   
  6. JNIEXPORT jint JNICALL  
  7. Java_java_io_FileInputStream_readBytes(JNIEnv *env, jobject this,  
  8.         jbyteArray bytes, jint off, jint len) {  
  9.     return readBytes(env, this, bytes, off, len, fis_fd);  
  10. }  

 

 

    继续看io_util.c 里面:

   

Java代码    
收藏代码
  1. jint  
  2. readSingle(JNIEnv *env, jobject this, jfieldID fid) {  
  3.     jint nread;  
  4.     char ret;  
  5.     FD fd = GET_FD(this, fid);  
  6.     if (fd == -1) {  
  7.         JNU_ThrowIOException(env, "Stream Closed");  
  8.         return -1;  
  9.     }  
  10.     // 看出是一个一个的读取,fd 表示刚才文件描述的一种结构  
  11.     nread = IO_Read(fd, &ret, 1);  
  12.     if (nread == 0) { /* EOF */  
  13.         return -1;  
  14.     } else if (nread == JVM_IO_ERR) { /* error */  
  15.         JNU_ThrowIOExceptionWithLastError(env, "Read error");  
  16.     } else if (nread == JVM_IO_INTR) {  
  17.         JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);  
  18.     }  
  19.     return ret & 0xFF;  
  20. }  

 

     

     关于IO_Read 的东西,在io_util_md.h 有定义:

    

Java代码    
收藏代码
  1. /* 
  2.  * HPI是一个与主机通信的并行接口 
  3.  * Route the routines through HPI 
  4.  */  
  5. #define IO_Write JVM_Write  
  6. #define IO_Sync JVM_Sync  
  7. <strong>#define IO_Read JVM_Read</strong>  
  8. #define IO_Lseek JVM_Lseek  
  9. #define IO_Available JVM_Available  
  10. #define IO_SetLength JVM_SetLength  

 

    关于JVM_Read 我在jvm.h 里面看到

   

Java代码    
收藏代码
  1. /* 
  2.    // 从文件里面读取 a char array 
  3.  * Read data from a file decriptor into a char array. 
  4.  * // 文件的来源 
  5.  * fd        the file descriptor to read from. 
  6.    // 读出来的存放位置 
  7.  * buf       the buffer where to put the read data. 
  8.    // 读的字节数 
  9.  * nbytes    the number of bytes to read. 
  10.  * 
  11.  * This function returns -1 on error, and 0 on success. 
  12.  */  
  13. JNIEXPORT jint JNICALL  
  14. JVM_Read(jint fd, char *buf, jint nbytes);  

   

    然后在jvm.cpp 里面找到

    关于这段代码,大神告诉我是宏定义,关于C和C++ 的东西,我已经无力回天啦。

    当然我们知道了介绍,可以理解这里会让调系统的read 方法。

    这可以参考:“操作系统read 的原理实现”,google 一下很多,这里就不解释了

    jvm.cpp 里面有很多关于IO这块的,可以去看看,但是都是 宏定义。。

    关于linux 下的这些代码,还有涉及一下阻塞等东西,以后在去研究一下操作系统的东西吧。

 

Java代码    
收藏代码
  1. JVM_LEAF(jint, JVM_Read(jint fd, char *buf, jint nbytes))  
  2.   JVMWrapper2("JVM_Read (0x%x)", fd);  
  3.   
  4.   //%note jvm_r6  
  5.   return (jint)os::restartable_read(fd, buf, nbytes);  
  6. JVM_END  

   

    

小结:

     1.本想了解下底层怎么操作的,但是大概了解下了,最终到read  或者write 的时候,一些基础知识不够,还是不能透彻,但是也足够我们大致了解了。

      2.按上面的思路可以看出大概的思路,虽然没写write 的过程,但是最终都是通过流,或者说字符数组在内存里面的一些操作进行,包括我们用装饰器模式搞了很多其他流,基本原理一样,仅仅为了方便加了额外的功能。

      3. 有不对的地方还请指出,仅仅是个人学习,分享作用

转载于:https://my.oschina.net/u/138995/blog/297537

你可能感兴趣的文章
均匀分布随机函数的实现
查看>>
Domino的压缩数据库的Load Compact命令
查看>>
C#注释标签
查看>>
Mysql中的事件
查看>>
Javascript 高级程序设计笔记 (cha4 变量作用域和内存)
查看>>
推荐一些C#相关的网站、资源和书籍
查看>>
linux nohup
查看>>
我的友情链接
查看>>
从换钱的最少货币数谈动态规划
查看>>
“.中国”域名总量超35.2万:2015年12月份净增9.4万
查看>>
1月份.top域名总量15强:西数等8家中国商上榜
查看>>
PageRank算法
查看>>
Ubuntu 卸载 网易云音乐
查看>>
linux bind命令解说与实例
查看>>
灾难恢复
查看>>
etcd 在超大规模数据场景下的性能优化
查看>>
UI2CODE再进化!结合Redux的框架升级!
查看>>
程序架构与设计(Java语言)
查看>>
BackTrack5利用路由PIN码破解无线路由WPA2密钥
查看>>
[java理论篇]--java的集合框架
查看>>