在用java批量復制文件時,用的是帶緩沖區的字符流,結果復制后的文件比原來的文件要大,代碼如下:
public static void main(String[] args) throws IOException { File file = new File("D:\\aaa\\原文件.PDF"); String fileName = "D:\\aaa\\復制的文件"; for(int i=0;i < 10; i++){ // FileUtils.copyFile(file, new File(fileName + i + ".PDF")); BufferedReader reader = new BufferedReader(new FileReader(file)); BufferedWriter writer = new BufferedWriter(new FileWriter(new File(fileName + i + ".PDF"))); String data = null; while((data = reader.readLine()) != null){ writer.write(data); writer.newLine(); writer.flush(); } writer.close(); reader.close(); // BufferedInputStream input = new BufferedInputStream(new FileInputStream(file)); // BufferedOutputStream output = new BufferedOutputStream( // new FileOutputStream(new File(fileName + i + ".PDF"))); // // int len = -1; // byte[] data = new byte [1024];//一次讀取1M // while ((len = input.read(data)) != -1){ // output.write(data,0,len); // } // // output.close(); // input.close(); System.out.println("復制了第:" + i + " 個文件"); } System.out.println("復制完成!"); }
復制后的效果如下圖:
可以發現,復制后的文件大小和原文件是不一樣的,這里是因為我復制的是PDF文件,而不是普通的文本文件,所以這里不能使用字符流BufferedReader,而應該使用字節流inputStream
下面總結一下字節流與字符流的區別與各自的使用場景:
- Java 中的字節流處理的最基本單位為 1 個字節,通常用來處理二進制數據。字節流類 InputStream 和 OutputStream 類均為抽象類,代表了基本的輸入字節流和輸出字節流。
- Java 中的字符流處理的最基本的單元是 Unicode 代碼單元(大小2字節),通常用來處理文本數據。
區別:
- 字節流操作的基本單元是字節;字符流操作的基本單元是字符
- 字節流默認不使用緩沖區;字符流使用緩沖區
- 字節流通常用於處理二進制數據,不支持直接讀寫字符;字符流通常用於處理文本數據
- 在讀寫文件需要對文本內容進行處理:按行處理、比較特定字符的時候一般會選擇字符流;僅僅讀寫文件,不處理內容,一般選擇字節流
特征:
- 以 stream 結尾都是字節流,reader 和 writer 結尾是字符流
- InputStream 是所有字節輸入流的父類,OutputStream 是所有字節輸出流的父類
- Reader 是字符輸入流的父類,Writer 是字符輸出流的父類
常見的字節流:
- 文件流:FileOutputStream 和 FileInputStream
- 緩沖流:BufferedOutputStream 和 BufferedInputStream
- 對象流:ObjectOutputStream 和 ObjectInputStream
常見的字符流:
- 字節轉字符流:InputStreamReader 和 OutputStreamWriter
- 緩沖字符流:PrintWriter 和 BufferedReader
可以這樣理解文件復制的過程:
字符流:二進制數據 --編碼-> 字符編碼表 --解碼-> 二進制數據
字節流:二進制數據 —> 二進制數據
所以問題就是出現在編碼和解碼的過程中,既然是字符的編碼表,那它就是包含所有的字符,但是字符的數量是有限的,這就意味着它不能表示一些超過編碼表的字符,因為根本不存在表中。所以,JVM 會使用一些字符進行替換,基本上都是亂碼(所以大小會發生變化),而且如果有一個數據恰好是-1,那么讀取就會中斷,引起數據丟失。