1. 程式人生 > >Java io FileDescriptor介紹及使用

Java io FileDescriptor介紹及使用

來源:http://www.cnblogs.com/skywang12345/p/io_09.html

FileDescriptor 介紹

FileDescriptor 是“檔案描述符”。
FileDescriptor 可以被用來表示開放檔案、開放套接字等。
以FileDescriptor表示檔案來說:當FileDescriptor表示某檔案時,我們可以通俗的將FileDescriptor看成是該檔案。但是,我們不能直接通過FileDescriptor對該檔案進行操作;若需要通過FileDescriptor對該檔案進行操作,則需要新建立FileDescriptor對應的FileOutputStream,再對檔案進行操作。


in, out, err介紹

  1. (01) in  -- 標準輸入(鍵盤)的描述符  
  2. (02) out -- 標準輸出(螢幕)的描述符  
  3. (03) err -- 標準錯誤輸出(螢幕)的描述符 

它們3個的原理和用法都類似,下面我們通過out來進行深入研究。

out 的作用和原理

out是標準輸出(螢幕)的描述符。但是它有什麼作用呢?
我們可以通俗理解,out就代表了標準輸出(螢幕)。若我們要輸出資訊到螢幕上,即可通過out來進行操作;但是,out又沒有提供輸出資訊到螢幕的介面(因為out本質是FileDescriptor物件,而FileDescriptor沒有輸出介面)。怎麼辦呢?
很簡單,我們建立out對應的“輸出流物件”,然後通過“輸出流”的write()等輸出介面就可以將資訊輸出到螢幕上。如下程式碼:

    try {  
        FileOutputStream out = new FileOutputStream(FileDescriptor.out);  
        out.write('A');  
        out.close();  
    } catch (IOException e) {  
    }  

執行上面的程式,會在螢幕上輸出字母'A'。

為了方便我們操作,java早已為我們封裝好了“能方便的在螢幕上輸出資訊的介面”:通過System.out,我們能方便的輸出資訊到螢幕上。
因此,我們可以等價的將上面的程式轉換為如下程式碼:
System.out.print('A');

下面講講上面兩段程式碼的原理

    public final class FileDescriptor {  
     
        private int fd;  
     
        public static final FileDescriptor out = new FileDescriptor(1);  
          
        private FileDescriptor(int fd) {  
            this.fd = fd;  
            useCount = new AtomicInteger();  
        }  
     
        ...  
    }  

檢視看out的定義。它的定義在FileDescriptor.java中,相關原始碼如下:

從中,可以看出
(01) out就是一個FileDescriptor物件。它是通過建構函式FileDescriptor(int fd)建立的。
(02) FileDescriptor(int fd)的操作:就是給fd物件(int型別)賦值,並新建一個使用計數變數useCount。
fd物件是非常重要的一個變數,“fd=1”就代表了“標準輸出”,“fd=0”就代表了“標準輸入”,“fd=2”就代表了“標準錯誤輸出”。

FileOutputStream out = new FileOutputStream(FileDescriptor.out); 就是利用建構函式FileOutputStream(FileDescriptor fdObj)來建立“Filed.out對應的FileOutputStream物件”。

關於System.out是如何定義的。可以參考" 深入瞭解System.out.println("hello world"); "
TODO

通過上面的學習,我們知道,我們可以自定義標準的檔案描述符[即,in(標準輸入),out(標準輸出),err(標準錯誤輸出)]的流,從而完成輸入/輸出功能;但是,java已經為我們封裝好了相應的介面,即我們可以更方便的System.in, System.out, System.err去使用它們。
另外,我們也可以自定義“檔案”、“Socket”等的檔案描述符,進而對它們進行操作。參考下面示例程式碼中的testWrite(), testRead()等介面。

示例程式碼

原始碼如下(FileDescriptorTest.java):

    import java.io.PrintStream;  
    import java.io.FileDescriptor;  
    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.IOException;  
     
    /**  
     * FileDescriptor 測試程式  
     *  
     * @author skywang  
     */ 
    public class FileDescriptorTest {  
     
        private static final String FileName = "file.txt";  
        private static final String OutText = "Hi FileDescriptor";  
        public static void main(String[] args) {  
            testWrite();  
            testRead();  
     
            testStandFD() ;  
            //System.out.println(OutText);  
        }  
     
        /**  
         * FileDescriptor.out 的測試程式  
         *  
         * 該程式的效果 等價於 System.out.println(OutText);  
         */ 
        private static void testStandFD() {  
            // 建立FileDescriptor.out 對應的PrintStream  
            PrintStream out = new PrintStream(  
                    new FileOutputStream(FileDescriptor.out));  
            // 在螢幕上輸出“Hi FileDescriptor”  
            out.println(OutText);  
            out.close();  
        }  
     
        /**  
         * FileDescriptor寫入示例程式  
         *   
         * (01) 為了說明,"通過檔名建立FileOutputStream"與“通過檔案描述符建立FileOutputStream”物件是等效的  
         * (02) 該程式會在“該原始檔”所在目錄新建檔案"file.txt",並且檔案內容是"Aa"。  
         */ 
        private static void testWrite() {  
            try {  
                // 新建檔案“file.txt”對應的FileOutputStream物件  
                FileOutputStream out1 = new FileOutputStream(FileName);  
                // 獲取檔案“file.txt”對應的“檔案描述符”  
                FileDescriptor fdout = out1.getFD();  
                // 根據“檔案描述符”建立“FileOutputStream”物件  
                FileOutputStream out2 = new FileOutputStream(fdout);  
     
                out1.write('A');    // 通過out1向“file.txt”中寫入'A'  
                out2.write('a');    // 通過out2向“file.txt”中寫入'A'  
     
                if (fdout!=null)  
                    System.out.printf("fdout(%s) is %s\n",fdout, fdout.valid());  
     
                out1.close();  
                out2.close();  
     
            } catch(IOException e) {  
                e.printStackTrace();  
            }  
        }  
     
        /**  
         * FileDescriptor讀取示例程式  
         *  
         * 為了說明,"通過檔名建立FileInputStream"與“通過檔案描述符建立FileInputStream”物件是等效的  
         */ 
        private static void testRead() {  
            try {  
                // 新建檔案“file.txt”對應的FileInputStream物件  
                FileInputStream in1 = new FileInputStream(FileName);  
                // 獲取檔案“file.txt”對應的“檔案描述符”  
                FileDescriptor fdin = in1.getFD();  
                // 根據“檔案描述符”建立“FileInputStream”物件  
                FileInputStream in2 = new FileInputStream(fdin);  
     
                System.out.println("in1.read():"+(char)in1.read());  
                System.out.println("in2.read():"+(char)in2.read());  
     
                if (fdin!=null)  
                    System.out.printf("fdin(%s) is %s\n", fdin, fdin.valid());  
     
                in1.close();  
                in2.close();  
            } catch(IOException e) {  
                e.printStackTrace();  
            }  
        }  
    } 

執行結果

  1. fdout(java.io.FileDescriptor@2b820dda) is true
  2. in1.read():A  
  3. in2.read():a  
  4. fdin(java.io.FileDescriptor@675b7986) is true
  5. Hi FileDescriptor