Java FileInputStream

 1、序言 javascript

        IO操做,才程序中比較廣泛,JAVA 中提出了IO/NIO 的概念,也一直在說NIO 比IO快,一直不知道緣由,就想memcache 和ehcache 比較優劣同樣,這些東西得本身看看如何實現的,才 知道區別,從而才知道優劣以及試用範圍,而不單單是「據說」!這裏我能夠先了解下JAVA 如何操做IO的。 java

 

2、代碼示例 linux

       咱們先看看簡單文件操做: windows

       

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找到實現: app

   

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, jvm

   

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. }  

 

   

 

  好吧,上面代碼我也搞不明白- -,可是這幾句代碼: ide

  

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. 有不對的地方還請指出,僅僅是我的學習,分享做用

相關文章
相關標籤/搜索