兩分鐘理解令人頭疼的java核心IO操作

兩分鐘理解令人頭疼的java核心IO操作

什麼是IO操作

Java中I/O操作主要是指使用Java進行輸入,輸出操作. Java所有的I/O機制都是基於數據流進行輸入輸出,這些數據流表示了字符或者字節數據的流動序列。Java的I/O流提供了讀寫數據的標準方法。任何Java中表示數據源的對象都會提供以數據流的方式讀寫它的數據的方法。

IO數據流的是什麼

數據流是一串連續不斷的數據的集合,就象水管裡的水流,在水管的一端一點一點地供水,而在水管的另一端看到的是一股連續不斷的水流。數據寫入程序可以是一段、一段地向數據流管道中寫入數據,這些數據段會按先後順序形成一個長的數據流。對數據讀取程序來說,看不到數據流在寫入時的分段情況,每次可以讀取其中的任意長度的數據,但只能先讀取前面的數據後,再讀取後面的數據。不管寫入時是將數據分多次寫入,還是作為一個整體一次寫入,讀取時的效果都是完全一樣的。

"流是磁盤或其它外圍設備中存儲的數據的源點或終點。"

在電腦上的數據有三種存儲方式,一種是外存,一種是內存,一種是緩存。比如電腦上的硬盤,磁盤,U盤等都是外存,在電腦上有內存條,緩存是在CPU裡面的。外存的存儲量最大,其次是內存,最後是緩存,但是外存的數據的讀取最慢,其次是內存,緩存最快。這裡總結從外存讀取數據到內存以及將數據從內存寫到外存中。對於內存和外存的理解,我們可以簡單的理解為容器,即外存是一個容器,內存又是另外一個容器。那又怎樣把放在外存這個容器內的數據讀取到內存這個容器以及怎麼把內存這個容器裡的數據存到外存中呢?

文件的編碼

通俗的來說,字符編碼就是按照某種格式某種規定將字符存儲在計算機中

字符編碼有非常多,每個國家都有自己規定的字符編碼,常見的字符編碼有以下幾種:

GBK默認一個英文佔用一個字節 一箇中文佔用兩個字節utf-8 中文佔用三個字節 英文佔用一個字節

Java IO體系

基於字節的IO操作

兩分鐘理解令人頭疼的java核心IO操作

基於字符的IO操作

兩分鐘理解令人頭疼的java核心IO操作

文件的讀寫操作字節流:讀寫以字節為單位

字符流:讀寫以字符為單位 只適用於文本輸入流:讀操作的輸出流:寫操作的1 輸入流: 以InputStream ----Fileinputstream把文件作為字節流進行讀操作2.輸出流: 以OutputStream.----FileOutputStream把文件作為字節流進行寫操作

IO常用類

文件流:FileInputStream/FileOutputStream, FileReader/FileWriter

這四個類是專門操作文件流的,用法高度相似,區別在於前面兩個是操作字節流,後面兩個是操作字符流。它們都會直接操作文件流,直接與OS底層交互。因此他們也被稱為節點流

注意使用這幾個流的對象之後,需要關閉流對象,因為java垃圾回收器不會主動回收。不過在Java7之後,可以在 try() 括號中打開流,最後程序會自動關閉流對象,不再需要顯示地close。

package io;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

public class TestIO {

public static void FileInputStreamTest() throws IOException {

FileInputStream fis = new FileInputStream("tmp2.txt");

byte[] buf = new byte[1024];

int hasRead = 0;

//read()返回的是單個字節數據(字節數據可以直接專程int類型),但是read(buf)返回的是讀取到的字節數,真正的數據保存在buf中

while ((hasRead = fis.read(buf)) > 0) {

//每次最多將1024個字節轉換成字符串,這裡tmp2.txt中的字符小於1024,所以一次就讀完了

//循環次數 = 文件字符數 除以 buf長度

System.out.println(new String(buf, 0 ,hasRead));

/*

* 將字節強制轉換成字符後逐個輸出,能實現和上面一樣的效果。但是如果源文件是中文的話可能會亂碼

for (byte b : buf) {

char ch = (char)b;

if (ch != '\r')

System.out.print(ch);

}

*/

}

//在finally塊裡close更安全

fis.close();

}

public static void FileReaderTest() throws IOException {

try (

// 在try() 中打開的文件, JVM會自動關閉

FileReader fr = new FileReader("tmp2.txt")) {

char[] buf = new char[32];

int hasRead = 0;

// 每個char都佔兩個字節,每個字符或者漢字都是佔2個字節,因此無論buf長度為多少,總是能讀取中文字符長度的整數倍,不會亂碼

while ((hasRead = fr.read(buf)) > 0) {

// 如果buf的長度大於文件每行的長度,就可以完整輸出每行,否則會斷行。

// 循環次數 = 文件字符數 除以 buf長度

System.out.println(new String(buf, 0, hasRead));

// 跟上面效果一樣

// System.out.println(buf);

}

} catch (IOException ex) {

ex.printStackTrace();

}

}

public static void FileOutputStreamTest() throws FileNotFoundException, IOException {

try (

//在try()中打開文件會在結尾自動關閉

FileInputStream fis = new FileInputStream("tmp2.txt");

FileOutputStream fos = new FileOutputStream("tmp3.txt");

) {

byte[] buf = new byte[4];

int hasRead = 0;

while ((hasRead = fis.read(buf)) > 0) {

//每讀取一次就寫一次,讀多少就寫多少

fos.write(buf, 0, hasRead);

}

System.out.println("write success");

} catch (IOException e) {

e.printStackTrace();

}

}

public static void FileWriterTest() throws IOException {

try (FileWriter fw = new FileWriter("tmp4.txt")) {

fw.write("天王蓋地虎\r\n");

fw.write("寶塔鎮河妖\r\n");

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) throws IOException {

//FileInputStreamTest();

//FileReaderTest();

//FileOutputStreamTest();

FileWriterTest();

}

}


  • 包裝流:PrintStream/PrintWriter/Scanner

PrintStream可以封裝(包裝)直接與文件交互的節點流對象OutputStream, 使得編程人員可以忽略設備底層的差異,進行一致的IO操作。因此這種流也稱為處理流或者包裝流。

PrintWriter除了可以包裝字節流OutputStream之外,還能包裝字符流Writer

Scanner可以包裝鍵盤輸入,方便地將鍵盤輸入的內容轉換成我們想要的數據類型。

  • 字符串流:StringReader/StringWriter

這兩個操作的是專門操作String字符串的流,其中StringReader能從String中方便地讀取數據並保存到char數組,而StringWriter則將字符串類型的數據寫入到StringBuffer中(因為String不可寫)。

  • 轉換流:InputStreamReader/OutputStreamReader

這兩個類可以將字節流轉換成字符流,被稱為字節流與字符流之間的橋樑。我們經常在讀取鍵盤輸入(System.in)或網絡通信的時候,需要使用這兩個類

  • 緩衝流:BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream

總結:

  1. FileInputStream/FileOutputStream 需要逐個字節處理原始二進制流的時候使用,效率低下

  2. FileReader/FileWriter 需要組個字符處理的時候使用

  3. StringReader/StringWriter 需要處理字符串的時候,可以將字符串保存為字符數組

  4. ·PrintStream/PrintWriter 用來包裝FileOutputStream 對象,方便直接將String字符串寫入文件

  5. ·Scanner 用來包裝System.in流,很方便地將輸入的String字符串轉換成需要的數據類型

  6. ·InputStreamReader/OutputStreamReader , 字節和字符的轉換橋樑,在網絡通信或者處理鍵盤輸入的時候用

  7. ·BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream , 緩衝流用來包裝字節流後者字符流,提升IO性能,BufferedReader還可以方便地讀取一行,簡化編程。


分享到:


相關文章: