Java中I/O操作主要是指使用Java進行輸入,輸出操作. Java所有的I/O機制都是基于數據流進行輸入輸出,這些數據流表示了字符或者字節數據的流動序列。
數據流是一串連續不斷的數據的集合,就象水管里的水流,在水管的一端一點一點地供水,而在水管的另一端看到的是一股連續不斷的水流。數據寫入程序可以是一段、一段地向數據流管道中寫入數據,這些數據段會按先后順序形成一個長的數據流。對數據讀取程序來說,看不到數據流在寫入時的分段情況,每次可以讀取其中的任意長度的數據,但只能先讀取前面的數據后,再讀取后面的數據(不能隨機讀取)。不管寫入時是將數據分多次寫入,還是作為一個整體一次寫入,讀取時的效果都是完全一樣的。
簡而言之:數據流是一組有序,有起點和終點的字節的數據序列。包括輸入流和輸出流。
當程序需要讀取數據的時候,就會建立一個通向數據源的連接,這個數據源可以是文件,內存,或是網絡連接。類似的,當程序需要寫入數據的時候,就會建立一個通向目的地的連接。
數據流分類:
流序列中的數據既可以是未經加工的原始二進制數據,也可以是經一定編碼處理后符合某種格式規定的特定數據。因此Java中的流分為兩種: 1) 字節流:數據流中最小的數據單元是字節 2) 字符流:數據流中最小的數據單元是字符, Java中的字符是Unicode編碼,一個字符占用兩個字節。
概覽
Java.io包中最重要的就是5個類和一個接口。5個類指的是File、OutputStream、InputStream、Writer、Reader;一個接口指的是Serializable。掌握了這些就掌握了Java I/O的精髓了。
Java I/O主要包括如下3層次:
- 流式部分——最主要的部分。如:OutputStream、InputStream、Writer、Reader等
- 非流式部分——如:File類、RandomAccessFile類和FileDescriptor等類
- 其他——文件讀取部分的與安全相關的類,如:SerializablePermission類,以及與本地操作系統相關的文件系統的類,如:FileSystem類和Win32FileSystem類和WinNTFileSystem類。
主要類如下:
- File(文件特征與管理):用于文件或者目錄的描述信息,例如生成新目錄,修改文件名,刪除文件,判斷文件所在路徑等。
- InputStream(字節流,二進制格式操作):抽象類,基于字節的輸入操作,是所有輸入流的父類。定義了所有輸入流都具有的共同特征。
- OutputStream(字節流,二進制格式操作):抽象類。基于字節的輸出操作。是所有輸出流的父類。定義了所有輸出流都具有的共同特征。
- Reader(字符流,文本格式操作):抽象類,基于字符的輸入操作。
- Writer(字符流,文本格式操作):抽象類,基于字符的輸出操作。
- RandomAccessFile(隨機文件操作):它的功能豐富,可以從文件的任意位置進行存取(輸入輸出)操作。

I/O流
java.io包里有4個基本類:InputStream、OutputStream及Reader、Writer類,它們分別處理字節流和字符流。
其他各種各樣的流都是由這4個派生出來的。

按來源/去向分類:
- File(文件): FileInputStream, FileOutputStream, FileReader, FileWriter
- byte[]:ByteArrayInputStream, ByteArrayOutputStream
- Char[]: CharArrayReader, CharArrayWriter
- String: StringBufferInputStream, StringReader, StringWriter
- 網絡數據流:InputStream, OutputStream, Reader, Writer
InputStream
InputStream 為字節輸入流,它本身為一個抽象類,必須依靠其子類實現各種功能,此抽象類是表示字節輸入流的所有類的超類。 繼承自InputStream 的流都是向程序中輸入數據的,且數據單位為字節(8bit);
InputStream是輸入字節數據用的類,所以InputStream類提供了3種重載的read方法.Inputstream類中的常用方法:
- public abstract int read( ):讀取一個byte的數據,返回值是高位補0的int類型值。若返回值=-1說明沒有讀取到任何字節讀取工作結束。
- public int read(byte b[ ]):讀取b.length個字節的數據放到b數組中。返回值是讀取的字節數。該方法實際上是調用下一個方法實現的
- public int read(byte b[ ], int off, int len):從輸入流中最多讀取len個字節的數據,存放到偏移量為off的b數組中。
- public int available( ):返回輸入流中可以讀取的字節數。注意:若輸入阻塞,當前線程將被掛起,如果InputStream對象調用這個方法的話,它只會返回0,這個方法必須由繼承InputStream類的子類對象調用才有用,
- public long skip(long n):忽略輸入流中的n個字節,返回值是實際忽略的字節數, 跳過一些字節來讀取
- public int close( ) :使用完后,必須對我們打開的流進行關閉。
來看看幾種不同的InputStream:
- FileInputStream把一個文件作為InputStream,實現對文件的讀取操作
- ByteArrayInputStream:把內存中的一個緩沖區作為InputStream使用
- StringBufferInputStream:把一個String對象作為InputStream
- PipedInputStream:實現了pipe的概念,主要在線程中使用
- SequenceInputStream:把多個InputStream合并為一個InputStream
OutputStream
OutputStream提供了3個write方法來做數據的輸出,這個是和InputStream是相對應的。
- public void write(byte b[ ]):將參數b中的字節寫到輸出流。
- public void write(byte b[ ], int off, int len) :將參數b的從偏移量off開始的len個字節寫到輸出流。
- public abstract void write(int b) :先將int轉換為byte類型,把低字節寫入到輸出流中。
- public void flush( ) : 將數據緩沖區中數據全部輸出,并清空緩沖區。
- public void close( ) : 關閉輸出流并釋放與流相關的系統資源。
幾種不同的OutputStream:
- ByteArrayOutputStream:把信息存入內存中的一個緩沖區中
- FileOutputStream:把信息存入文件中
- PipedOutputStream:實現了pipe的概念,主要在線程中使用
- SequenceOutputStream:把多個OutStream合并為一個OutStream
Reader和InputStream類似;Writer和OutputStream類似。
有兩個需要注意的:
- InputStreamReader : 從輸入流讀取字節,在將它們轉換成字符。
- BufferReader :接受Reader對象作為參數,并對其添加字符緩沖器,使用readline()方法可以讀取一行。
如何選擇I/O流
- 確定是輸入還是輸出
- 輸入:輸入流 InputStream Reader
- 輸出:輸出流 OutputStream Writer
- 明確操作的數據對象是否是純文本
- 是:字符流 Reader,Writer
- 否:字節流 InputStream,OutputStream
- 明確具體的設備。
- 文件:
- 讀:FileInputStream,, FileReader,
- 寫:FileOutputStream,FileWriter
- 數組:
- byte[ ]:ByteArrayInputStream, ByteArrayOutputStream
- char[ ]:CharArrayReader, CharArrayWriter
- String:
- StringBufferInputStream(已過時,因為其只能用于String的每個字符都是8位的字符串), StringReader, StringWriter
- Socket流
- 鍵盤:用System.in(是一個InputStream對象)讀取,用System.out(是一個OutoutStream對象)打印
- 是否需要轉換流
- 是,就使用轉換流,從Stream轉化為Reader、Writer:InputStreamReader,OutputStreamWriter
- 是否需要緩沖提高效率
- 是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader, BufferedWriter
- 是否需要格式化輸出
示例代碼
- 將標準輸入(鍵盤輸入)顯示到標準輸出(顯示器),支持字符。
char ch;BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); //將字節流轉為字符流,帶緩沖try { while ((ch = (char) in.read()) != -1){ System.out.print(ch); }} catch (IOException e) { e.printStackTrace();}
- 將AtomicityTest.java的內容打印到顯示器
方法一:BufferedReader in = new BufferedReader(new FileReader("AtomicityTest.java"));String s;try { while ((s = in.readLine()) != null){ System.out.println(s); } in.close();} catch (IOException e) { e.printStackTrace();}方法二:FileReader in = new FileReader("AtomicityTest.java");int b;try { while ((b = in.read()) != -1){ System.out.print((char)b); } in.close();} catch (IOException e) { e.printStackTrace();}方法三:(有可能出現亂碼)FileInputStream in = new FileInputStream("AtomicityTest.java");int n = 50;byte[] buffer = new byte[n];try { while ((in.read(buffer,0,n) != -1 && n > 0)){ System.out.print(new String(buffer)); } in.close();} catch (IOException e) { e.printStackTrace();}
- 將文件A的內容拷貝到文件B
FileInputStream in = new FileInputStream("AtomicityTest.java");FileOutputStream out = new FileOutputStream("copy.txt");int b;while ((b = in.read()) != -1){ out.write(b);}out.flush();in.close();out.close();
- 將標準輸入的內容寫入文件
Scanner in = new Scanner(System.in);FileWriter out = new FileWriter("systemIn.log");String s;while (!(s = in.nextLine()).equals("Q")){ out.write(s + "");}out.flush();out.close();in.close();