節點流(檔案流)
阿新 • • 發佈:2020-08-07
# 節點流
## FileReader和FileWriter
字元流(cha[]陣列)
### FileReader讀入資料的基本操作
#### 過程
1. 例項化File類的物件,指明要操作的檔案
注意:
* 在@Test測試中的相對路徑是相對於當前Module
* 在main函式的相對路徑是相對於當前工程
2. 提供具體的流
3. 資料的讀入過程
4. 流的關閉操作
5. try-catch-finally異常處理
#### 說明
* 一定要注意最後流的關閉
* read()的理解:返回讀入的一個字元。如果達到檔案末尾,返回-1
* 異常的處理:為了保證流資源一定可以執行關閉的操作,需要使用try-catch-finally來處理
* 讀入的檔案(hello.txt)一定要存在,否則會報FileNotFoundException異常
#### 程式碼實現
```java
@org.junit.Test
public void test1(){
FileReader fileReader = null;
try {
//1. 例項化File類的物件,指明要操作的檔案
//注意:在@Test測試中的相對路徑是相對於當前Module,在main函式的相對路徑是相對於當前工程
File file = new File("hello.txt");//相對路徑
//2. 提供具體的流
fileReader = new FileReader(file);
//3. 資料的讀入過程
//read():返回讀入的一個字元。如果達到檔案末尾,返回-1
//方式一
// int data = fileReader.read();
// while(data != -1){
// System.out.print((char)data);
// data = fileReader.read();
// }
//方式二:語法上針對方式一的修改
int data;
while((data = fileReader.read()) != -1){
System.out.println((char)data);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4. 流的關閉操作
try {
//防止最開始提供流是出現異常導致這裡是空指標,所以加一個判斷
if(fileReader != null){
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
#### 執行結果
此時的"hello.txt"文件中儲存的內容是hello
![o6Ij4.png](https://wx1.sbimg.cn/2020/08/06/o6Ij4.png)
#### 使用read()的過載方法
* read():返回讀入的一個字元。如果達到檔案末尾,返回-1
* read(char[] cbuf):返回每次讀入cbuf陣列中的字元的個數。如果達到檔案末尾,返回-1(常用)
* read(char cbuf[], int off, int len) (不常用)
##### read(char[] cbuf)的用法
1. 建立一個char的陣列cbuf
(舉例假定該陣列的長度為5)
>char[] cbuf = new char[5];
2. 建立len變數,儲存read(char[] cbuf)的返回值
(注意:返回值即為每次讀入cbuf陣列中的字元的個數)
3. 讀取資料
* 寫法一:迴圈遍歷
```java
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
```
* 寫法二:char[]型別和String型別轉換
```java
String str = new String(cbuf,0,len);
System.out.print(str);
```
https://www.cnblogs.com/CrabDumplings/p/13341279.html
![o91I2.png](https://wx1.sbimg.cn/2020/08/06/o91I2.png)
4. 流的關閉操作(不要忘記)
##### read(char[] cbuf)讀取資料時的注意事項
* 寫法一
```java
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
```
其中for迴圈時,i一定要小於len(每次讀入cbuf陣列中的字元的個數)而不是cbuf.length
* 畫圖說明:
![o9xOe.png](https://wx1.sbimg.cn/2020/08/06/o9xOe.png)
最後還剩下3個數據的時候:
* 如果for迴圈中的i小於cbuf.length(錯誤的寫法)
![o9rpk.png](https://wx1.sbimg.cn/2020/08/06/o9rpk.png)
最後的輸出為:helloWorld123ld
(其中hello為第一次的結果,World為第二次的結果,123ld為第三次的結果)
而檔案中的內容為helloWorld123,所以此時的寫法是錯誤的
* 如果for迴圈中的i小於len(正確的寫法)
![o9Ogn.png](https://wx2.sbimg.cn/2020/08/06/o9Ogn.png)
最後的輸出為:helloWorld123
(其中hello為第一次的結果,World為第二次的結果,123為第三次的結果)
* 寫法二
```java
String str = new String(cbuf,0,len);
System.out.print(str);
```
其中利用了String(char[] value, int offset, int count)構造器,而不是String(char[] value)構造器
* String(char[] value)構造器(錯誤的寫法)
錯誤原因與寫法一錯誤的方法相同
* String(char[] value, int offset, int count)構造器(正確的寫法)
讀取char[]陣列中角標0到角標len的內容,過程與寫法一正確的方法過程類似
### FileReader寫出資料的基本操作
#### 過程
1. 例項化File類的物件,指明要操作的檔案
2. 提供具體的流
3. 資料的寫出過程
4. 流的關閉操作
5. try-catch-finally異常處理
#### 說明
寫出操作,對應的File可以不存在。
* 如果不存在,在寫出的過程中,會自動建立此檔案
* 如果存在這個檔案
* 對原有檔案的覆蓋
流使用的構造器為
>FileWriter(file, false)
或者是
>FileWriter(file)
* 在原有檔案的基礎上追加內容(不會對原有檔案進行覆蓋)
流使用的構造器為
>FileWriter(file, true)
![o9TfM.png](https://wx2.sbimg.cn/2020/08/06/o9TfM.png)
#### 程式碼實現
```java
FileWriter fw1 = null;
FileWriter fw2 = null;
try {
//1. 提供File類的物件,指明寫出到的檔案
File file = new File("hi.txt");
//2. 提供FileWriter的物件,用於檔案的寫出
//覆蓋
fw1 = new FileWriter(file,false);
//不覆蓋
fw2 = new FileWriter(file,true);
//3. 寫出的操作
fw1.write("I have a dream!\n");
fw2.write("123\n");
} catch (IOException e) {
e.printStackTrace();
}finally {
//4. 關閉流資源
if(fw1 != null)
try {
fw1.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fw2 != null)
try {
fw2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
#### 執行結果
最開始hi.txt檔案中的內容為hello
執行程式碼後
![o9VQa.png](https://wx1.sbimg.cn/2020/08/06/o9VQa.png)
### 使用FileWriter和FileReader實現文字檔案的複製
#### 過程
1. 建立File類的物件,指明讀入和寫出的檔案
2. 建立輸入流和輸出流的物件
3. 資料的讀入和寫入操作
4. 關閉流資源
5. try-catch-finally異常處理
#### 說明
* 在讀取檔案檔案時,選擇read(char[] cbuf)的用法
* 在寫入檔案的時候,注意不要寫成
> fw.write(cbuf);
此時出現的錯誤和讀取操作時寫法一會出現的錯誤相同,不可以正確的讀取檔案中原本的內容
需要使用
>fw.write(cbuf,0,len);
讀取cbuf陣列中角標為0的元素到角標為len的元素
* 在最後關閉流資源的時候,一定要注意兩個流都要關閉,即使其中一個流在關閉的時候丟擲異常另一個流也要關閉
有兩種寫法
* 寫法一
```java
finally {
//4. 關閉流資源
if(fr != null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fw != null)
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
* 寫法二
```java
finally {
//4. 關閉流資源
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
```
#### 程式碼實現
```java
public void test4(){
FileReader fr = null;
FileWriter fw = null;
try {
//1. 建立File類的物件,指明讀入和寫出的檔案
File file1 = new File("hello.txt");
File file2 = new File("hi.txt");
//2. 建立輸入流和輸出流的物件
fr = new FileReader(file1);
fw = new FileWriter(file2,true);
//3. 資料的讀入和寫入操作
char[] cbuf = new char[5];
int len;//記錄每次讀入到cbuf陣列中字元的個數
while((len = fr.read(cbuf)) != -1){
//每次寫出len個字元
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4. 關閉流資源
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
#### 執行結果
![oG51G.png](https://wx1.sbimg.cn/2020/08/06/oG51G.png)
#### 注意
字元流不能處理圖片檔案等位元組資料!!!
## FileInputStream和FileOutputStream
位元組流(byte[])
### 使用FileInputStream和FileOutputStream實現文字檔案的複製
#### 過程
1. 建立File類的物件,指明讀入和寫出的檔案
2. 建立輸入流和輸出流的物件
3. 資料的讀入和寫入操作
4. 關閉流資源
5. try-catch-finally異常處理
#### 程式碼實現
```java
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcfile = new File("殷志源.png");
File destfile = new File("丸子.png");
fis = new FileInputStream(srcfile);
fos = new FileOutputStream(destfile);
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
```
#### 執行結果
![oRznG.png](https://wx1.sbimg.cn/2020/08/07/oRznG.png)
![oRHMT.png](https://wx2.sbimg.cn/2020/08/07/oRHMT.png)
### 指定路徑下檔案的複製的方法
複製視訊
```java
public void copyFile(String srcPath, String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcfile = new File(srcPath);
File destfile = new File(destPath);
fis = new FileInputStream(srcfile);
fos = new FileOutputStream(destfile);
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
[![ocIS1.png](https://wx1.sbimg.cn/2020/08/07/ocIS1.png)](https://sbimg.cn/image/ocIS1)
[![od4o2.png](https://wx1.sbimg.cn/2020/08/07/od4o2.png)](https://sbimg.cn/image/od4o2)
## 位元組流和字元流使用的注意事項
* 對於文字檔案(.txt, .java, .c, .cpp......),使用字元流來處理
* 對於非文字檔案(.jpg, .mp3, .mp4, .avi, .doc, .ppt......),使用位元組流來處理
* 如果只是想複製文字檔案,也可以使用位元組流(流在此時只是個搬運的作用)
* 非文字只可以用位元組