Java的IO(Input/Output)流是處理數據輸入和輸出的基礎。無論是讀取文件、寫入文件,還是通過網絡傳輸數據,IO流都無處不在。對于剛接觸Java的新手,理解IO流可能會有些困惑,但別擔心,今天我們將一步步走過它,讓你從一個小白變成IO流的小達人!
一、什么是IO流?
在Java中,IO流是指數據流向的方向,它包括了輸入流(InputStream)和輸出流(OutputStream)兩大類。
-
輸入流(InputStream):用于讀取數據的流,例如從文件、鍵盤或網絡中讀取數據。
-
輸出流(OutputStream):用于向目標寫入數據的流,比如將數據寫入文件、控制臺或網絡中。
IO流的核心概念就是“數據流向”,可以理解為你從某個地方讀取數據,或者將數據寫入到某個地方。
二、IO流的分類
Java中的IO流有很多種,按用途大致可以分為兩大類:
-
字節流(Byte Stream):處理所有類型的I/O,適用于所有類型的數據(包括圖片、音頻、視頻等二進制數據)。字節流的父類是
InputStream
和OutputStream
。 -
字符流(Character Stream):專門用于處理文本數據(即字符數據),它是對字節流的封裝,采用字符編碼方式來讀取和寫入文本數據。字符流的父類是
Reader
和Writer
。
詳細解釋
所謂這些流就是一個鏈接文件的管道,字節,字符流,就是代表在管道里面流轉的數據不一樣輸入流就是將文件內容通過管道發送到程序。輸出流就是從程序寫入到文件里面。流的分類按照流的方向:輸入流、輸出流按照流的內容:字節流、字符流
字節流:適合操作所有類型的文件 字符流:適合操作純文本文件
他們之間組合形成了四個類
字節輸入流 FileInputStream
字符輸出流 FileOutputStream
字符輸入流 FileReader
字符輸出流 FileWriter他們都繼承兩個基類 InputStream OutputStream他們本質就是一些對象,擁有一些操作數據的方法。
創建對象
字節輸入流為例
FileOutputStream fos = new FileOutputStream("文件路徑");
其他就是替換類名就行了。也可以利用多態寫法,換成基類
注意:絕對路徑和相對路徑的差別,在開發多人項目的時候一般使用相對路徑,就是在你的項目中的路徑。
絕對路徑就是存放在磁盤的路徑,但當你拿別人的項目的時候一旦文件存放的磁盤不一樣就會拋出異常。方法:字符和字節一樣都有方法
讀入方法,單個字節讀入int b = fos.read();int b;while((b=is.read())!=-1){System.out.print((char)b);}
這樣效率非常慢,而且不能存放漢字,因為一個漢字的字節占位不是一,
我們一般利用數組傳入,一次性傳多個byte[] buffer = new byte[5];
int len;//定義一個變量記住每次讀取了多少個字節,因為有可能都不滿數組。
while((len=is.read(buffer))!=-1){ System.out.print(new String(buffer,0,len));//解釋一下,len是每次讀取的字節數,//即從0開始,截取len個字節,轉換成字符串輸出//String s = new String(buffer);// System.out.println(s);//這樣寫的話,每次都會將buffer中的字節全部轉換成字符串,如果源文件只有4個字節,那么就會將buffer中多余的字節轉換成亂碼 //但是無法解決亂碼問題。//解決方法,一次讀完所以的字節,只適合小文件,大文件可能會造成內存溢出//readAllBytes()//讀取文件所有字節//byte[] bytes = is.readAllBytes();//System.out.println(new String(bytes));
文件字節輸出流 FileOutputStream作用:將數據寫入文件覆蓋管道,會覆蓋原來的數據FileOutputStream fos = new FileOutputStream("路徑");//與字節輸入流一樣,也有一個字節輸出流管道與源文件路徑接通//FileOutputStream(File file)//與源文件路徑接通(一般用)//FileOutputStream(String path)//寫數據文件會自動創建文件FileOutputStream fos = new FileOutputStream("file_io_stream\\src\\text02.txt");//同樣的文件字節輸出流也有將讀到文件里面的方法,但是和輸入流也存在亂碼問題,解決方式也一樣//一個字節寫入一個字節 write()fos.write('9');//也有數組方式byte[] bytess = {97,98,99,100};//將文字編碼成字節byte[] bytesss = "我愛中國".getBytes();fos.write(bytesss);fos.write(bytess);//也能寫一部分字節數組出去//將字節1-2寫出去//但是在寫漢字的時候依然會有亂碼問題//write(字節數組,起始位置,寫多少個字節出去)fos.write(bytesss,0,9);//但是這樣寫是將文件清空在寫的,所以不能重復寫入。//要追加添加文件,需要使用帶參數的構造方法//追加參數,追加數據FileOutputStream fos1 = new FileOutputStream("file_io_stream\\src\\text02.txt",true);//注意在這些流用完后一定要關閉流fos.close();fos1.close();
?但是我們流在使用后必須關閉,但是一定程序在流關閉之前就拋出異常,導致流沒有關閉,造成內存泄漏所以我們規定了流的寫法格式
try(){
}catch()
{
}
try(只能放置資源對象,用完后最終會自動調用close方法FileInputStream fis=new FileInputStream(src);FileOutputStream fos=new FileOutputStream(dest,true);){byte[] buf=new byte[1024];int len;while((len=fis.read(buf))!=-1){fos.write(buf,0,len);//讀取多少字節就寫多少字節}}catch (Exception e){e.printStackTrace();}}
?字符和字節完全一樣,只是方法的名稱有些不一樣
讀入
try( FileReader fr = new FileReader("file_io_stream\\src\\zi_fu_stream\\zi_fu_text");){char [] cbuf = new char[1024];//不建議單個字符讀入,會拖累程序int b;while((b = fr.read(cbuf)) != -1){//打印出來System.out.print(new String(cbuf,0,b));}//字符沒有全部讀入方式//拓展:文件字符輸入流每次讀多個字符,性能較好,而且讀中文沒有亂碼}catch (Exception e){e.printStackTrace();}
輸出
//五個方法//write(char c)//寫入一個字符//write(String str)//寫入一個字符串//write(char[] cbuf)//寫入一個字符數組//write(char[] cbuf,int off,int len)//寫入一個字符數組的一部分//flush()//刷新緩沖區,將數據寫入文件
?我們一般就使用字符串?
緩沖流
認識緩沖流緩沖字節輸入流 BufferedInputStream緩沖字節輸出流BufferedOutputStream緩沖字符輸入流 BufferedReader緩沖字符輸出流 BufferedWriter
其實就是提高性能而且,在外面套了一層殼使用方法一模一樣就是換了類名
字符緩沖輸入流新增功能:按照行讀取字符
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {String line;while ((line = reader.readLine()) != null) {// 處理每一行}} catch (IOException e) {e.printStackTrace();}
三、簡單的字節流示例
先從一個最基礎的例子開始:用字節流讀取和寫入文件。
1. 讀取文件內容
import java.io.FileInputStream;
import java.io.IOException;
?
public class FileReaderExample {public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("input.txt")) {int byteData;while ((byteData = fis.read()) != -1) {System.out.print((char) byteData);}} catch (IOException e) {e.printStackTrace();}}
}
解釋:
-
FileInputStream
是字節流的一個例子,用來讀取文件數據。 -
fis.read()
方法逐個字節讀取文件的內容。 -
try-with-resources
語法可以自動關閉資源,避免手動關閉。
2. 寫入文件內容
import java.io.FileOutputStream;
import java.io.IOException;
?
public class FileWriterExample {public static void main(String[] args) {try (FileOutputStream fos = new FileOutputStream("output.txt")) {String message = "Hello, Java IO!";fos.write(message.getBytes()); ?// 將字符串轉換為字節數組并寫入文件} catch (IOException e) {e.printStackTrace();}}
}
解釋:
-
FileOutputStream
用于將數據寫入文件。 -
write()
方法將字節數據寫入文件。
四、簡單的字符流示例
字符流適用于文本文件的讀取和寫入,它會自動進行字符編碼的轉換。
1. 讀取文本文件
import java.io.FileReader;
import java.io.IOException;
?
public class FileReaderExample {public static void main(String[] args) {try (FileReader fr = new FileReader("input.txt")) {int charData;while ((charData = fr.read()) != -1) {System.out.print((char) charData); ?// 輸出每個字符}} catch (IOException e) {e.printStackTrace();}}
}
2. 寫入文本文件
import java.io.FileWriter;
import java.io.IOException;
?
public class FileWriterExample {public static void main(String[] args) {try (FileWriter fw = new FileWriter("output.txt")) {String message = "Hello, Java IO with Character Streams!";fw.write(message); ?// 直接寫入字符串} catch (IOException e) {e.printStackTrace();}}
}
五、常用的IO流類和方法
-
FileInputStream/FileOutputStream:用于字節流讀寫文件。
-
FileReader/FileWriter:用于字符流讀寫文件。
-
BufferedReader/BufferedWriter:用于高效地讀取和寫入字符數據,適合處理大量文本數據。
1. 使用 BufferedReader
讀取文件
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
?
public class BufferedReaderExample {public static void main(String[] args) {try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {String line;while ((line = br.readLine()) != null) {System.out.println(line); ?// 逐行讀取文件內容}} catch (IOException e) {e.printStackTrace();}}
}
2. 使用 BufferedWriter
寫入文件
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
?
public class BufferedWriterExample {public static void main(String[] args) {try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {String message = "Buffered Writer Example";bw.write(message); ?// 寫入內容} catch (IOException e) {e.printStackTrace();}}
}
六、IO流的實際應用場景
-
讀取和寫入文件:最常見的應用,比如讀取配置文件、寫入日志文件等。
-
網絡通信:通過Socket連接進行網絡數據的發送和接收。
-
數據加密與解密:處理加密文件的讀取和寫入。
-
多線程并發訪問文件:使用IO流結合多線程技術,處理并發文件操作。
最后介紹一下io框架
commons-io.jar
為了簡化上面的方法,io框架將上面的內容封裝成了一個個內容,方便我們直接調用,說白了上面學了都沒用,直接用框架就行,但是我們還是要掌握數據流動的方式。
1. IOUtils
處理輸入/輸出流的工具類。
方法列表與作用
方法 | 作用 |
---|---|
copy(InputStream, OutputStream) | 復制輸入流到輸出流(自動緩沖) |
toString(InputStream, Charset) | 將輸入流內容轉為字符串 |
readLines(InputStream, Charset) | 按行讀取輸入流為字符串列表 |
示例代碼
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
?
public class IOUtilsExample {public static void main(String[] args) throws IOException {// 1. 復制流try (InputStream in = new FileInputStream("input.txt");OutputStream out = new FileOutputStream("output.txt")) {IOUtils.copy(in, out); // 將 input.txt 內容復制到 output.txt}
?// 2. 輸入流轉字符串try (InputStream in = new FileInputStream("input.txt")) {String content = IOUtils.toString(in, StandardCharsets.UTF_8);System.out.println(content); // 輸出文件內容}
?// 3. 按行讀取try (InputStream in = new FileInputStream("input.txt")) {List<String> lines = IOUtils.readLines(in, StandardCharsets.UTF_8);lines.forEach(System.out::println); // 逐行打印}}
}
2. FileUtils
文件操作工具類。
方法列表與作用
方法 | 作用 |
---|---|
readFileToString(File, Charset) | 讀取文件內容為字符串 |
writeStringToFile(File, String, Charset) | 將字符串寫入文件 |
copyFile(File, File) | 復制文件 |
copyDirectory(File, File) | 復制整個目錄 |
deleteDirectory(File) | 遞歸刪除目錄 |
cleanDirectory(File) | 清空目錄內容 |
示例代碼
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
?
public class FileUtilsExample {public static void main(String[] args) throws IOException {// 1. 讀取文件為字符串String content = FileUtils.readFileToString(new File("test.txt"), StandardCharsets.UTF_8);System.out.println(content);
?// 2. 寫入字符串到文件FileUtils.writeStringToFile(new File("output.txt"), "Hello Commons IO", StandardCharsets.UTF_8);
?// 3. 復制文件FileUtils.copyFile(new File("source.txt"), new File("dest.txt"));
?// 4. 復制目錄FileUtils.copyDirectory(new File("srcDir"), new File("destDir"));
?// 5. 刪除目錄FileUtils.deleteDirectory(new File("oldDir"));
?// 6. 清空目錄FileUtils.cleanDirectory(new File("tempDir"));}
}
3. FilenameUtils
文件路徑處理工具類。
方法列表與作用
方法 | 作用 |
---|---|
getExtension(String) | 獲取文件擴展名 |
removeExtension(String) | 移除文件擴展名 |
concat(String, String) | 安全拼接路徑 |
示例代碼
import org.apache.commons.io.FilenameUtils;
?
public class FilenameUtilsExample {public static void main(String[] args) {// 1. 獲取擴展名String ext = FilenameUtils.getExtension("data.json"); // 返回 "json"
?// 2. 移除擴展名String name = FilenameUtils.removeExtension("image.jpg"); // 返回 "image"
?// 3. 路徑拼接String fullPath = FilenameUtils.concat("/home/user", "docs/file.txt"); // 返回 "/home/user/docs/file.txt"
?System.out.println(ext + ", " + name + ", " + fullPath);}
}
4. FileAlterationObserver
監控文件/目錄變化的工具。
方法作用
-
監聽文件創建、修改、刪除事件。
示例代碼
import org.apache.commons.io.monitor.*;
import java.io.File;
?
public class FileMonitorExample {public static void main(String[] args) throws Exception {File dir = new File("monitored_dir");FileAlterationObserver observer = new FileAlterationObserver(dir);observer.addListener(new FileAlterationListenerAdaptor() {@Overridepublic void onFileCreate(File file) {System.out.println("文件創建: " + file.getName());}@Overridepublic void onFileDelete(File file) {System.out.println("文件刪除: " + file.getName());}});
?FileAlterationMonitor monitor = new FileAlterationMonitor(1000); // 輪詢間隔1秒monitor.addObserver(observer);monitor.start();
?// 保持程序運行(實際應用可能需要線程管理)Thread.sleep(60_000);monitor.stop();}
}
關鍵說明
//這里涉及到Maven工程管理,意思就是在idea里面下載這個jar包,方便自己使用,可以在我的博客里面找有關于Maven工程的介紹
-
依賴引入:需在項目中添加 Commons IO 依賴(如 Maven):
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.13.0</version> </dependency>
-
異常處理:所有示例需處理
IOException
(此處簡化為throws
)。 -
資源釋放:使用
try-with-resources
確保流自動關閉。
通過這些示例,可以快速實現文件操作、流處理及目錄監控功能。
七、總結
Java的IO流非常強大且靈活,掌握了它,你就能輕松地處理文件、網絡等數據輸入輸出操作。雖然剛開始可能有些晦澀,但通過不斷的實踐和理解,你會逐步熟悉并掌握這些技術。
如果你有其他問題或需要更詳細的案例,隨時留言!希望這篇博客能幫助你順利入門Java IO流。