前言
java 的 IO 流有很多類,常見常用的也就是字節流 InputStream 和 OutputStream 輸入輸出流,這是字節流兩個頂級父類(當然上面還有接口),還有 FileReader 和 FileWriter 輸入輸出流,這是字符流兩個頂級父類
輸入和輸出可以理解爲相對於內存或者屏幕來說的,從磁盤讀取到內存中是輸入,寫進磁盤則表示輸出。所以很好理解, InputStream 和 FileReader 用來做讀取數據操作,OutputStream 和 FileWriter 用來做把數據寫入磁盤的操作
下面這有一張菜鳥教程中的圖片,很清晰的展示了各個類之間的父子關係
字節流
常用的 OutputStream 和 InputStream 是輸出流和輸入流,二者都是抽象類,然後我們常用其中的 FileOutStream 和 FileInputStream,還有一個緩衝流 BufferedOutputStream 和 BufferedInputStream 是一個緩衝器,構造器分別接收 OutputStream 和 InputStream 的參數類型
字節流的追加就是在構造器的時候第二個參數傳入 true 即可,不傳默認是 false 就是完全覆蓋
OutputStream 字節輸出流
字節輸出流,下圖中我們知道 java.io 包中有如下這些字節輸出流的類,其中 OutputStream 是一個抽象類
其實絕大部分程序員最常用的也就是 FileOutputStream 和 BufferedOutputStream
小例子如下,其寫入文件磁盤只能接收 int 和 byte 類型,int 就是 ascall 碼對應的數字,字節就是一個字節,注意可不是 char 類型
如果我們不是用 buffer 也行,如果使用的話buffer.close()
必加,不加的話 buffer 中的字節沒辦法存進磁盤中!!!
public class IOOperation {
@Test
public void fun() throws IOException {
FileOutputStream stream = new FileOutputStream("src\\test\\java\\temp.txt");
BufferedOutputStream buffer = new BufferedOutputStream(stream);
buffer.write(new byte[]{'a', 'b', 'c'});
buffer.close();
stream.close();
}
}
注意點
- 如果使用了 buffer 注意要加``buffer.close()`否則不會將緩衝區的內容寫進磁盤!
InputStream 字節輸入流
字節輸入流,下圖中我們知道 java.io 包中有如下這些字節輸出流的類,其中 InputStream 是一個抽象類
其實絕大部分程序員最常用的也就是 FileInputStream 和 BufferedInputStream
public class IOOperation {
@Test
public void fun() throws IOException {
FileInputStream stream = new FileInputStream("src\\test\\java\\temp.txt");
BufferedInputStream buffer = new BufferedInputStream(stream);
System.out.println(buffer.read());
System.out.println(buffer.read());
System.out.println(buffer.read());
System.out.println(buffer.read());
buffer.close();
stream.close();
}
}
注意點
- 如果使用了 buffer 加不加``buffer.close()`都可以直接看到控制檯有正常輸出,這一點與輸出流是不同的
- 使用 read 方法如果讀到沒有字節了,會直接返回 -1,read 方法返回 int 類型
- 每次使用 read 方法之後,一個字節一個字節的往後讀
字符流
Writer 和 Reader 分別是字符輸出流和字符輸入流,二者都是抽象類,然後往下繼承的子類 OutputStreamWriter 和 InputStreamReader 都是實體類
字符流的追加就是在構造器的時候第二個參數傳入 true 即可,不傳默認是 false 就是完全覆蓋
Writer 字符輸出流
字符輸出流
其實一般情況下我們使用最多也就是 FileWriter 和 BufferedWriter
下面有個小例子,展示的是追加文件,先進入下一行,然後寫上 aaabbbccc
public class IOOperation {
@Test
public void fun() throws IOException {
FileWriter writer = new FileWriter("src\\test\\java\\temp.txt", true);
BufferedWriter buffer = new BufferedWriter(writer);
buffer.newLine();
buffer.write("aaa");
buffer.append("bbb").append("ccc");
buffer.close();
writer.close();
}
}
注意點
- 字符流除了有 write 方法,還有 append 方法,write 方法沒有返回值且不可接受 null,但是 append 方法似乎就要靈活一些了,可以接收 null,寫入磁盤就是 null 的字符串,而且有返回值,返回就是字符流本身,因此可以不斷的
.append("").append("")
的形式 - buffer 必加上 close,否則磁盤沒有內容
Reader 字符輸入流
字符輸入流
其實一般情況下我們使用最多也就是 FIleReader 和 BufferedReader
我們直接看下面的例子即可
public class IOOperation {
@Test
public void fun() throws IOException {
FileReader reader = new FileReader("src\\test\\java\\temp.txt");
BufferedReader buffer = new BufferedReader(reader);
System.out.println(buffer.read());
System.out.println(buffer.readLine());
buffer.close();
reader.close();
}
}
注意點
- 與字節流相似,輸入字符流在使用 buffer 時候沒有加 close 關掉 buffer 也一樣是可以把文件中的內容讀取到控制檯中的,相比輸出字符流就必須要加上 buffer 的 close 方法了
- read 方法返回 int 型,也就是一個字符的 ascall 碼,readLine 方法可以返回當前位置後一整行的字符串類型
- 如果 read 方法讀不到字符了它會返回 -1,如果 readLine 方法讀不到行了它會返回 null 的字符串
二者區別
字節流讀取字節,字符流讀取一個字符
字符流是可以設置編碼方式的
字符流更加靈活,推薦文本文件使用
使用場景
如果是操作文本文件,我建議直接使用字符流來操作,簡單便捷,若是圖片或者其他文件(電腦中的文件都是二進制形式文件,都可以使用字節流操作),我就推薦直接使用字節流來操作了
其他注意點
-
Write 輸出流的 flush() 操作是指,一般 IO 操作在有緩衝區的情況下,調用 close() 方法緩衝區纔會被輸出到磁盤中,如果直接執行 flush 可以在緩衝區沒有滿的時候手動輸出一次到磁盤
-
字符流設置編碼方式可以通過 InputStreamReader 或者 OutputStreamWriter 的構造器來做,第二個參數傳輸編碼名字,這兩個類父類分別是 Reader 和 Writer,子類分別是 FileReader 和 FIleWriter。並且我查看了源碼發現如果不傳編碼方式,它會執行這段代碼
Charset.defaultCharset().name()
,它讀的是配置的語言編碼,或者說自己環境的語言編碼 -
如果是中文,java 字節流也是可以讀取的但是讀取的東西可能就不好認識了,比如說一個“啊”讀取到屏幕上顯示 229 149 138