IO流詳解
一、輸入流
位元組輸入流
FileInputSteam
1、構造方法:
public FileInputStream(File file) {}
public FileInputStream(FileDescriptor fdObj){}
public FileInputStream(String name){}
2、read方法:
// 每次讀取一個位元組
public int read(){}
// 讀取b.length個位元組到byte陣列中
public int read(byte b[]){}
// 從輸入流中讀取len個位元組到位元組陣列中
public int read(byte b[], int off, int len){}
3、檔案讀取:
1、read()
每次讀取一個位元組資料,返回位元組數,如果到達檔案末尾,返回-1。
文字
abc
public static void method_01(String filePath) throws IOException {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
// 每次讀取一個位元組
for (int i = 0; i < 4; i++) {
int read = inputStream.read();
System.out.println(read);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
// 關閉IO流
inputStream.close();
}
}
}
執行結果:
97
98
99
-1
從執行結果可以看出,前三次讀取到了資料,返回了對應的ASCII碼,當讀取到檔案末尾的時候,則返回-1。
2、read(byte[] b)
讀入緩衝區的位元組總數,如果到達檔案末尾,則返回-1。
文字:
abcdefg
宣告一個大於真實資料的byte陣列讀取資料。
public static void method_02(String filePath) throws IOException {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
// 宣告的長度大於真實資料長度
byte[] bytes = new byte[20];
int length = inputStream.read(bytes);
System.out.println("位元組陣列長度:" + bytes.length + " 讀取到的資料位元組長度:" + length);
for (byte b : bytes) {
System.out.print(b + " | ");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
inputStream.close();
}
}
}
執行結果:
位元組陣列長度:20 讀取到的資料位元組長度:7
97 | 98 | 99 | 100 | 101 | 102 | 103 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
可以看出,當我們byte陣列的長度大於位元組陣列的真實長度之後,那麼後面的空間全部使用0做補位,這也恰恰反映了另外一個問題,我們在使用byte[]陣列讀取檔案的時候,千萬不要說我設定足夠大的長度,就可以高枕無憂提高讀取效率,如果遇到小檔案,那麼也是很容易造成效率低下的。
3、read(byte b[], int off, int len)
讀入緩衝區的位元組總數,如果讀取到檔案末尾,則返回-1;
文字:
abcdefg
宣告一個固定大小的byte陣列,迴圈讀取資料
我們的文字有七個位元組,宣告瞭一個2個長度的陣列,應該迴圈四次,第五次讀取的時候返回-1。
public static void method_03(String filePath) throws IOException {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
// 宣告2個長度
byte[] bytes = new byte[2];
int i = 0;
while (i < 5) {
int length = inputStream.read(bytes, 0, bytes.length);
System.out.println("第" + (i + 1) + "次讀取,length: " + length);
System.out.println("開始輸出:");
for (int j = 0; j < length; j++) {
System.out.print(bytes[j] + " | ");
}
System.out.println();
i++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
inputStream.close();
}
}
}
執行結果:
第1次讀取,length: 2
開始輸出:
97 | 98 |
第2次讀取,length: 2
開始輸出:
99 | 100 |
第3次讀取,length: 2
開始輸出:
101 | 102 |
第4次讀取,length: 1
開始輸出:
103 |
第5次讀取,length: -1
開始輸出:
注意:
可能有的朋友會遇到我之前遇到的問題,他的文字里面寫了漢字或者標點符號,會出現亂碼,我們給文字最後再追加一箇中文,並且把每次讀取到的byte陣列轉換成String進行輸出,看會出現什麼情況。
public static void method_03(String filePath) throws IOException {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
byte[] bytes = new byte[2];
int i = 0;
while (i < 5) {
inputStream.read(bytes, 0, bytes.length);
// 將byte[]轉換成string
String s = new String(bytes, StandardCharsets.UTF_8);
System.out.println(s);
i++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
inputStream.close();
}
}
}
結果:
ab
cd
ef
g�
��
剛開始腦子抽了,感覺這是什麼問題,怎麼會亂碼呢,如果稍微上點心的都會發現,中文佔3個byte位元組,你用2個儲存那鐵定亂碼呀。那麼你肯定想過那我把陣列宣告大一點不就好了,如果你這麼想過,那你可能還不知道社會的險惡。
那麼到底怎麼辦呢?真的就沒辦法了嗎?接下來我們用一個例子來學習如何解決這種問題。
一個?:
將文字中的內容讀取出來,輸出到控制檯。
既然我們知道,上面的亂碼是因為英文和中文佔用的位元組數不同引起的,那我們要是知道了整個檔案佔用的位元組長度,那麼不就一次性可以讀取出來了。恰好FileInputStream提供了這樣一個方法(available),讓我們可以獲取到整個檔案所佔用的位元組數。
public static void printConsole(String filePath) throws IOException {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
// 獲取到整個文字佔用的整個位元組數
int available = inputStream.available();
// 宣告陣列
byte[] bytes = new byte[available];
// 讀取資料
int readLength = inputStream.read(bytes, 0, available);
String s = new String(bytes, StandardCharsets.UTF_8);
System.out.println("讀取到的長度:" + readLength + " available:" + available);
System.out.println("讀取到的內容: " + s);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
inputStream.close();
}
}
}
結果:
讀取到的長度:30 available:30
讀取到的內容: abcdef一個程式設計師的成長
這樣的話,我們就可以讀取到文字中完整的內容了。只有瞭解了這些,那麼才會瞭解我們的寫檔案下載的時候為什麼要判斷 讀取到的位元組數 !=-1 這樣的操作,不然真的很難記住。
字元輸入流
FileReader
1、構造方法:
public FileReader(String fileName){};
public FileReader(File file){};
public FileReader(FileDescriptor fd){};
2、read方法:
public int read(){};
public int read(char cbuf[], int offset, int length){};
public int read(char cbuf[]){};
3、檔案讀取:
FileReader的read方法讀取出來的是一個獨立的字元(char),所以面對英文和中文的混合,我們不會因為佔用位元組的不同從而導致出現亂碼的情況。
文字:
abcdef一個程式設計師的成長
讀取內容的程式碼:
public static void method_01(String filePath) throws IOException {
FileReader fr = null;
try {
fr = new FileReader(filePath);
int c;
// 每次讀取一個字元,等於-1即表示檔案讀取到末尾
while ((c = fr.read()) != -1) {
System.out.println((char) c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (null != fr) {
fr.close();
}
}
結果:
a
b
c
d
e
f
一
個
程
序
員
的
成
長
根據結果可以看出,read()讀取出來的每次就是一個單獨的字元,那麼另外兩個read方法跟位元組流讀取都是一樣的。
更多內容請關注微信公眾號: