節點流(檔案流)
節點流
FileReader和FileWriter
字元流(cha[]陣列)
FileReader讀入資料的基本操作
過程
-
例項化File類的物件,指明要操作的檔案
注意:
-
在@Test測試中的相對路徑是相對於當前Module
-
在main函式的相對路徑是相對於當前工程
-
-
提供具體的流
-
資料的讀入過程
-
流的關閉操作
-
try-catch-finally異常處理
說明
- 一定要注意最後流的關閉
- read()的理解:返回讀入的一個字元。如果達到檔案末尾,返回-1
- 異常的處理:為了保證流資源一定可以執行關閉的操作,需要使用try-catch-finally來處理
- 讀入的檔案(hello.txt)一定要存在,否則會報FileNotFoundException異常
程式碼實現
@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
使用read()的過載方法
- read():返回讀入的一個字元。如果達到檔案末尾,返回-1
- read(char[] cbuf):返回每次讀入cbuf陣列中的字元的個數。如果達到檔案末尾,返回-1(常用)
- read(char cbuf[], int off, int len) (不常用)
read(char[] cbuf)的用法
-
建立一個char的陣列cbuf
(舉例假定該陣列的長度為5)
char[] cbuf = new char[5];
-
建立len變數,儲存read(char[] cbuf)的返回值
(注意:返回值即為每次讀入cbuf陣列中的字元的個數)
-
讀取資料
- 寫法一:迴圈遍歷
for (int i = 0; i < len; i++) { System.out.print(cbuf[i]); }
- 寫法二:char[]型別和String型別轉換
String str = new String(cbuf,0,len); System.out.print(str);
-
流的關閉操作(不要忘記)
read(char[] cbuf)讀取資料時的注意事項
-
寫法一
for (int i = 0; i < len; i++) { System.out.print(cbuf[i]); }
其中for迴圈時,i一定要小於len(每次讀入cbuf陣列中的字元的個數)而不是cbuf.length
-
畫圖說明:
最後還剩下3個數據的時候:
-
如果for迴圈中的i小於cbuf.length(錯誤的寫法)
最後的輸出為:helloWorld123ld
(其中hello為第一次的結果,World為第二次的結果,123ld為第三次的結果)
而檔案中的內容為helloWorld123,所以此時的寫法是錯誤的
-
如果for迴圈中的i小於len(正確的寫法)
最後的輸出為:helloWorld123
(其中hello為第一次的結果,World為第二次的結果,123為第三次的結果)
-
-
-
寫法二
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寫出資料的基本操作
過程
- 例項化File類的物件,指明要操作的檔案
- 提供具體的流
- 資料的寫出過程
- 流的關閉操作
- try-catch-finally異常處理
說明
寫出操作,對應的File可以不存在。
- 如果不存在,在寫出的過程中,會自動建立此檔案
- 如果存在這個檔案
-
對原有檔案的覆蓋
流使用的構造器為
FileWriter(file, false)
或者是
FileWriter(file)
-
在原有檔案的基礎上追加內容(不會對原有檔案進行覆蓋)
流使用的構造器為
FileWriter(file, true)
-
程式碼實現
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
執行程式碼後
使用FileWriter和FileReader實現文字檔案的複製
過程
- 建立File類的物件,指明讀入和寫出的檔案
- 建立輸入流和輸出流的物件
- 資料的讀入和寫入操作
- 關閉流資源
- try-catch-finally異常處理
說明
-
在讀取檔案檔案時,選擇read(char[] cbuf)的用法
-
在寫入檔案的時候,注意不要寫成
fw.write(cbuf);
此時出現的錯誤和讀取操作時寫法一會出現的錯誤相同,不可以正確的讀取檔案中原本的內容
需要使用
fw.write(cbuf,0,len);
讀取cbuf陣列中角標為0的元素到角標為len的元素
-
在最後關閉流資源的時候,一定要注意兩個流都要關閉,即使其中一個流在關閉的時候丟擲異常另一個流也要關閉
有兩種寫法
- 寫法一
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(); } } }
- 寫法二
finally { //4. 關閉流資源 try { if(fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } try { if(fw != null) fw.close(); } catch (IOException e) { e.printStackTrace(); } }
程式碼實現
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();
}
}
}
執行結果
注意
字元流不能處理圖片檔案等位元組資料!!!
FileInputStream和FileOutputStream
位元組流(byte[])
使用FileInputStream和FileOutputStream實現文字檔案的複製
過程
- 建立File類的物件,指明讀入和寫出的檔案
- 建立輸入流和輸出流的物件
- 資料的讀入和寫入操作
- 關閉流資源
- try-catch-finally異常處理
程式碼實現
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();
}
}
執行結果
指定路徑下檔案的複製的方法
複製視訊
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();
}
}
}
位元組流和字元流使用的注意事項
- 對於文字檔案(.txt, .java, .c, .cpp......),使用字元流來處理
- 對於非文字檔案(.jpg, .mp3, .mp4, .avi, .doc, .ppt......),使用位元組流來處理
- 如果只是想複製文字檔案,也可以使用位元組流(流在此時只是個搬運的作用)
- 非文字只可以用位元組流操作