流式 IO 是傳統 IO,通過構造輸入輸出流,講信息從一個地方讀取,輸出到另一個地方。常見的有讀取文件以及寫入文件。
基本 API
流失 IO 基本可以分為兩個門派,一個以 InputStream 和 OutputStream 為代表的老牌 IO,一個以 Reader 和 Writer 為代表的新派 IO。
這里僅僅展示最常用 API,其余 API 可以查閱 jdk API
輸入
基本輸入
InputStream | Reader |
---|---|
InputStream 面向字節流 IO 不能很好的支持 Unicode 字符 | Reader 面向字符流 IO 能很好的支持 Unicode 字符 |
FileInputStream 文件讀取流 | FileReader 文件讀取 |
ByteArrayInputStream | CharArrayReader |
裝飾器輸入
基本輸入中的流對象,都可以作為裝飾器對象的構造器參數
InputStream | Reader | 功能 |
---|---|---|
DataInputStream | 包含用於讀取基本數據類型的全部接口 | |
BufferedInputStream | BufferedReader | 本質上不提供接口,只是向進程添加緩沖功能。與接口對象搭配 |
輸出
基本輸出
OutputStream | Writer |
---|---|
FileOutputStream | FileWriter |
ByteArrayOutputStream | CharArrayWriter |
裝飾器輸出
OutputStream | Writer | 功能 |
---|---|---|
DataOutputStream | 包含用於寫入基本數據類型的全部接口 | |
PrintStream | PrintWriter | 用於產生格式化輸出 |
BufferedOutputStream | BufferedWriter | 本質上並不提供接口,只是向進程添加緩沖功能。與接口對象搭配 |
常見用法
讀取文件
使用 FileInputStream 讀取
下面例子將輸入流放入 try-with-resource 塊中,以實現資源的自動關閉,本文下面例子都將采用這種形式。
這里可以看到,是一個字節一個字節的讀,所以要將其轉為 char 才能正常展示,否則展示的都是字節。 由於 InputStream 是字節流,因此,這里讀取到的中文展示亂碼。
public class Read {
/**
* 使用 FileInputStream 直接讀取
* 由於 InputStream 不支持 Unicode 編碼,所以中文顯示會亂碼
*/
public static void fileInputStream() {
try (
FileInputStream input = new FileInputStream("Read.java")
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStream();
}
}
輸出:
package cyrus.file_io.iostream;
import java.io.FileInputStream;
public class Read {
/**
* ä½¿ç¨ FileInputStream ç´æ¥è¯»å
* ç±äº InputStream 䏿¯æ Unicode ç¼ç ï¼æä»¥ä¸ææ¾ç¤ºä¼ä¹±ç
*/
public static void fileInputStream() {
try (
FileInputStream input = new FileInputStream("Read.java")
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStream();
}
}
使用 BufferedInputStream 裝飾器讀取
以下例子使用 FileInputStream 構造一個 BufferedInputStream 裝飾器,該適配器的主要作用是會將讀取到的內容填充進緩沖區,其余用法和 FileInputStream 一樣。InputStream 是字節流,因此,這里讀取到的中文展示亂碼。
public class Read {
/**
* 使用 FileInputStream 構造一個 BufferedInputStream 裝飾器,讀取,該讀取會使用緩沖區
* 由於 InputStream 不支持 Unicode 編碼,所以中文會亂碼
*/
public static void fileInputStreamWithBuffer() {
try (
BufferedInputStream input = new BufferedInputStream(new FileInputStream("Read.java"))
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStreamWithBuffer();
}
}
輸出:
package cyrus.file_io.iostream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Read {
/**
* ä½¿ç¨ FileInputStream æé ä¸ä¸ª BufferedInputStream è£
饰å¨ï¼è¯»åï¼è¯¥è¯»åä¼ä½¿ç¨ç¼å²åº
* ç±äº InputStream 䏿¯æ Unicode ç¼ç ï¼æä»¥ä¸æä¼ä¹±ç
*/
public static void fileInputStreamWithBuffer() {
try (
BufferedInputStream input = new BufferedInputStream(new FileInputStream("Read.java"))
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStreamWithBuffer();
}
}
使用 FileReader 進行讀取
使用 FileReader 直接讀取,這里 Reader 支持 Unicode 編碼,因此中文不會亂碼,正常顯示
public class Read {
/**
* 使用 FileReader 直接讀取
* 由於 Reader 支持 Unicode 編碼,因此中文不會亂碼,正常顯示
*/
public static void fileReader() {
try (
FileReader reader = new FileReader("Read.java")
) {
int n = 0;
while (n != -1) {
n = reader.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReader();
}
}
輸出:
package cyrus.file_io.iostream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
public class Read {
/**
* 使用 FileReader 直接讀取
* 由於 Reader 支持 Unicode 編碼,因此中文不會亂碼,正常顯示
*/
public static void fileReader() {
try (
FileReader reader = new FileReader("Read.java")
) {
int n = 0;
while (n != -1) {
n = reader.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReader();
}
}
使用 BufferedReader 裝飾器讀取
這里使用 FileReader 構造一個 BufferedReader 裝飾器,BufferedReader 的主要作用是會將讀取到的內容填入緩沖區,並且 BufferedReader 的 lines() 方法將返回一個 stream 流,操作更方便。
public class Read {
/**
* 使用 FileReader 構造一個 BufferedReader 裝飾器,讀取,該讀取會使用緩沖區
* 由於 Reader 支持 Unicode 編碼,因此中文不會亂碼,正常顯示
*/
public static void fileReaderWithBuffer() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
reader.lines().forEach(System.out::println);
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReaderWithBuffer();
}
}
輸出:
package cyrus.file_io.iostream;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
public class Read {
/**
* 使用 FileReader 構造一個 BufferedReader 裝飾器,讀取,該讀取會使用緩沖區
* 由於 Reader 支持 Unicode 編碼,因此中文不會亂碼,正常顯示
*/
public static void fileReaderWithBuffer() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
reader.lines().forEach(System.out::println);
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReaderWithBuffer();
}
}
使用 DataInputStream 適配器讀取字符串
這里 buildString() 方法讀取當前文件,將其拼裝為字符串輸出,ByteArrayInputStream 讀取該字符串的 byte 數組,然后轉化為 DataInputStream 適配器進行讀取字符串內容。
DataInputStream 主要用於讀取基本數據類型
public class Read {
/**
* 使用 ByteArrayInputStream 構造 DataInputStream 裝飾器,輸出字符串信息
*/
public static void dataInputStream() {
try (
DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(buildString().getBytes()))
) {
while (inputStream.available() != 0) {
System.out.print((char) inputStream.readByte());
}
} catch (Exception e) {
}
}
/**
* 通過目前 java 文件構建一個字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.dataInputStream();
}
}
寫入文件
使用 FileOutputStream 寫入
這里直接使用 FileOutputStream 讀取 buildString() 方法構造的字符串並將其寫入 Read.txt 文件
public class Read {
/**
* 使用 FileOutputStream 直接寫入字符串
*/
public static void fileOutputStream() {
try (
FileOutputStream output = new FileOutputStream("Read.txt")
) {
output.write(buildString().getBytes());
} catch (Exception e) {
}
}
/**
* 通過目前 java 文件構建一個字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileOutputStream();
}
}
輸出:實例截圖一部分
使用 BufferedOutputStream 適配器寫入
這里使用 FileOutputStream 構造一個 BufferedOutputStream 適配器,BufferedOutputStream 會使用到緩沖區,加快讀取寫入速度。
public class Read {
/**
* 使用 FileOutputStream 構造一個 BufferedOutputStream 裝飾器,讀取,該寫入會使用緩沖區
*/
public static void fileOutputStreamWithBuffer() {
try (
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream("Read.txt"));
) {
output.write(buildString().getBytes());
} catch (Exception e) {
}
}
/**
* 通過目前 java 文件構建一個字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileOutputStreamWithBuffer();
}
}
后面就不展示輸出了,所有的輸出都是輸出到當前工作目錄的Read.txt文件夾下,並且文件內容都是當前 .java 文件的內容
使用 FileWriter 寫入
public class Read {
/**
* 使用 FileWriter 直接寫入
*/
public static void fileWriter() {
try (
FileWriter writer = new FileWriter("Read.txt");
) {
writer.write(buildString());
} catch (Exception e) {
}
}
/**
* 通過目前 java 文件構建一個字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileWriter();
}
}
使用 PrintWriter 進行輸出
這里使用了兩層適配器,第一層是使用 FileWriter 構造一個 BufferedWriter,該適配器會使用緩沖區進行寫入,然后再使用 BufferedWriter 構造一個PrintWriter 適配器,使用該適配器的println()方法直接輸出到指定文件。
public class Read {
/**
* 使用 FileWriter 構造一個 BufferedWriter 裝飾器,該裝飾器會使用緩沖區,然后再使用 BufferedWriter 構造一個 PrintWriter裝飾器,使用 println 輸出到文件
*/
public static void fileWriterWithBuffer() {
try (
PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter("Read.txt")))
) {
writer.println(buildString());
} catch (Exception e) {
}
}
/**
* 通過目前 java 文件構建一個字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileWriterWithBuffer();
}
}
總結
流式IO 其實挺好理解的,一共分為兩套,InputStream、OutputStream 為一套,Reader 和 Writer 為一套,其中各自都有基本輸入輸出類和使用基本輸入輸出類構造的裝飾器輸入輸出類,裝飾器還能構造裝飾器,無限套娃。
如 new PrintWriter(new BufferedWriter(new FileWriter("Read.txt"))),這里就將 BufferedWriter 裝飾器裝配成了 PrintWriter 裝飾器,這樣這個 PrintWriter 就擁有了 BufferedWriter 的特性(使用緩沖區),以及他自己的特性。
文章為本人學習過程中的一些個人見解,漏洞是必不可少的,希望各位大佬多多指教,幫忙修復修復漏洞!!!
參考資料:java 編程思想
歡迎進入本人語雀文檔閱讀,格式更清晰哦:
https://www.yuque.com/docs/share/26bf2f91-b3d3-4b28-a43e-302a1e650d57?# 《流式 IO》