<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Java的基本使用之IO

      1、IO的基本介紹

      IO是指 Input/Output,即輸入和輸出。以內存為中心:

      • Input 指從外部讀入數據到內存,例如把文件從磁盤讀取到內存,從網絡讀取數據到內存等等。

      • Output 指把數據從內存輸出到外部,例如把數據從內存寫入到文件,把數據從內存輸出到網絡等等。

      Java 代碼是在內存中運行的,所以數據也必須讀到內存才能對其進行處理,數據在 Java 代碼中的最終表示方式無非是 byte數組,字符串等這些 Java 數據類型,都必須存放在內存里。

      從 Java 代碼來看,輸入實際上就是從外部,例如硬盤上的某個文件,把內容讀到內存,并且以 Java 提供的某種數據類型表示,例如,byte[]String,這樣,后續代碼才能處理這些數據。因為內存有“易失性”的特點,所以必須把處理后的數據以某種方式輸出,例如,寫入到文件。Output 實際上就是把 Java 表示的數據格式,例如,byte[]String等輸出到某個地方。

      IO 流是一種順序讀寫數據的模式,它的特點是單向流動。數據類似自來水一樣在水管中流動,所以我們把它稱為IO流。IO流以byte(字節)為最小單位,因此也稱為字節流。

       

      1.1、流的分類

      按操作數據單位不同分為:字節流、字符流

      按數據流的流向不同分為:輸入流、輸出流

      按流的角色不同分為:節點流、處理流

       Java 的 IO 流共涉及40多個類,但都是從 InputStream、OutputStream、Reader、Writer這四個抽象基類派生的。由這四個類派生出來的子類的名稱都以其父類名作為后綴。

       

       

      1.2、輸入/輸出字節流(InputStream / OutputStream)

      IO 流以 byte(字節)為最小單位,因此也稱為字節流。 在Java中,InputStream代表輸入字節流,OuputStream代表輸出字節流,這是最基本的兩種IO流。

      例如,我們要從磁盤讀入一個文件,包含6個字節,就相當于讀入了6個字節的數據。

      這6個字節是按順序讀入的,所以是輸入字節流。

      反過來,我們把6個字節從內存寫入磁盤文件,就是輸出字節流:

       

      1.3、字符流(Reader / Writer)

      如果我們需要讀寫的是字符,并且字符不全是單字節表示的 ASCII 字符,那么,按照字符 char 來讀寫顯然更方便,這種流稱為字符流。Java提供了ReaderWriter表示字符流,字符流傳輸的最小數據單位是char

      例如,我們把 char[] 數組 “Hi你好” 這4個字符用Writer字符流寫入文件,并且使用UTF-8編碼,得到的最終文件內容是8個字節,英文字符 H 和 i 各占一個字節,中文字符 “你好” 各占3個字節。反過來,我們用Reader讀取以UTF-8編碼的這8個字節,會從Reader中得到Hi你好這4個字符。因此,ReaderWriter本質上是一個能自動編解碼的InputStreamOutputStream。使用Reader,數據源雖然是字節,但我們讀入的數據都是char類型的字符,原因是Reader內部把讀入的byte做了解碼,轉換成了char。使用InputStream,我們讀入的數據和原始二進制數據一模一樣,是byte[]數組,但是我們可以自己把二進制byte[]數組按照某種編碼轉換為字符串。

      究竟使用Reader還是InputStream,要取決于具體的使用場景。如果數據源不是文本,就只能使用InputStream,如果數據源是文本,使用Reader更方便一些。WriterOutputStream是類似的。

       

      1.4、同步和異步IO

      同步IO是指,讀寫IO時代碼必須等待數據返回后才繼續執行后續代碼,它的優點是代碼編寫簡單,缺點是CPU執行效率低。

      而異步IO是指,讀寫IO時僅發出請求,然后立刻執行后續代碼,它的優點是CPU執行效率高,缺點是代碼編寫復雜。

      Java標準庫的包java.io提供了同步IO,InputStreamOutputStreamReaderWriter都是同步IO的抽象類,對應的具體實現類,以文件為例,有FileInputStreamFileOutputStreamFileReaderFileWriter

      java.nio則是異步IO。

       

      2、File 對象

      Java的標準庫java.io提供了File對象來操作文件和目錄。File對象既可以表示文件,也可以表示目錄。File 能新建、刪除、重命名文件和目錄,但 File 不能訪問文件內容本身,即只能操作文件或者目錄,但不能操作文件內容本身。如果需要訪問文件內容本身,需使用輸入/輸出流。

      2.1、構造File對象(new File())

      要構造一個File對象,需要傳入文件路徑:

      import java.io.*;
      public class Main {
          public static void main(String[] args) {
              File f = new File("C:\\Windows\\notepad.exe");
              System.out.println(f);
          }
      }

      構造File對象時,既可以傳入絕對路徑,也可以傳入相對路徑。File 對象中傳入的相對路徑是相對于你當前 Java 文件所處的項目的根目錄而言的,而不是相對于當前 Java 文件的路徑。

      (可以使用 \ 或者 / 作為路徑分隔符。因為 \ 在Java中是轉義字符,所以使用 \ 作為分隔符時需使用兩個 \ 即 \\ )

      //絕對路徑:以根目錄開頭的完整路徑
      File f = new File("C:\\Windows\\notepad.exe");
      File f = new File("C:/Windows/notepad.exe");
      
      //傳入相對路徑時,相對路徑前面加上當前項目的根目錄就是絕對路徑。比如下面當前目錄是C:\Docs
      File f1 = new File("sub\\javac"); // 則絕對路徑是C:\Docs\sub\javac
      File f3 = new File(".\\sub\\javac"); // 絕對路徑是C:\Docs\sub\javac
      File f3 = new File("..\\sub\\javac"); // 絕對路徑是C:\sub\javac

       

      2.2、創建和刪除文件(createNewFile()、delete())

      當File對象表示一個文件時,可以通過 File 對象的 createNewFile() 方法來創建一個新文件,如果創建成功,該方法將返回 true,如果該文件已經存在則返回 false,如果指定的目錄不存在將會拋出異常,不會自動創建目錄。

      //比如當前的項目根目錄為F:\JavaSE_WorkSpace\demo01
      File file = new File(".\\path\\file.txt");  //F:\JavaSE_WorkSpace\demo01\path\file.txt
      
      if (file.createNewFile()) {   //如果文件的目錄不存在將會報錯
          System.out.println("創建成功");
      }

      可以用 delete() 方法來刪除一個文件,當刪除成功時返回 true,否則返回 false,該方法不會因為沒有找到目錄而報錯

      File file = new File(".\\path\\file.txt");
      
      if (file.delete()) {
          System.out.println("刪除成功");
      }

       

      有些時候,程序需要讀寫一些臨時文件,File對象提供了createTempFile()來創建一個臨時文件,該方法將會在默認的臨時文件目錄下創建文件,比如:C:\Users\張三\AppData\Local\Temp\ 目錄下。

      可以用deleteOnExit()在JVM退出時自動刪除該臨時文件。

      File f = File.createTempFile("tmp-", ".txt"); // 提供臨時文件的前綴和后綴
      //f.deleteOnExit();    // 該方法將會在JVM退出時自動刪除該文件

       

      2.3、創建目錄

      和文件操作類似,File對象如果表示一個目錄,可以通過以下方法創建和刪除目錄:

      • boolean mkdir():創建當前File對象表示的目錄。只能創建一層目錄,如果父級不存在需要一層層調用先創建父級再創建子級目錄
      • boolean mkdirs():創建當前File對象表示的目錄。該方法可以創建多層,即在必要時會自動將不存在的父目錄也創建出來;
      • boolean delete():刪除當前File對象表示的目錄,當前目錄必須為空才能刪除成功。

       

      2.4、遍歷文件和目錄(list()、listFiles())

      當File對象表示一個目錄時,可以使用list()listFiles()列出目錄下的文件和子目錄名。

      list() 方法返回目錄下的文件或者子目錄的名稱字符串數組。listFiles() 方法返回目錄下的文件或者子目錄的 File 對象數組,listFiles() 提供了一系列重載方法,可以過濾不想要的文件和目錄。

      public static void main(String[] args) throws IOException {
          File f = new File("F:\\JavaSE_WorkSpace2\\day01");
          File[] fs1 = f.listFiles(); // 得到該目錄下的所有文件和子目錄
          printFiles(fs1);             
      
          File[] fs2 = f.listFiles(new FilenameFilter() {  //限制僅列出.exe文件
              public boolean accept(File dir, String name) {
                  return name.endsWith(".exe"); // 返回true表示接受該文件
              }
          });
          printFiles(fs2);
      }
      
      //封裝一個循環遍歷函數
      static void printFiles(File[] files) {
          if (files != null) {
              for (File f : files) {
                  System.out.println(f);
              }
          }
          System.out.println("遍歷結束");
      }

       

      2.5、File對象的一些其他方法

      File對象既可以表示文件,也可以表示目錄。特別要注意的是,構造一個File對象,即使傳入的文件或目錄不存在,代碼也不會出錯,因為構造一個File對象,并不會導致任何磁盤操作。只有當我們調用File對象的某些方法的時候,才真正進行磁盤操作。

      例如,調用isFile(),判斷該File對象是否是一個已存在的文件,調用isDirectory(),判斷該File對象是否是一個已存在的目錄。

      File對象獲取到一個文件時,還可以進一步判斷文件的權限和大小:

      • boolean canRead():是否可讀;
      • boolean canWrite():是否可寫;
      • boolean canExecute():是否可執行;
      • long length():文件字節大小。

      對目錄而言,是否可執行表示能否列出它包含的文件和子目錄。

      File f1 = new File("C:\\Windows");
      System.out.println(f1.isFile());          //false
      System.out.println(f1.isDirectory());    //true

       

       

      2.6、三種類型的路徑(絕對路徑、相對路徑、規范路徑)

      File 對象有三種形式表示的路徑,包括絕對路徑、相對路徑和規范路徑,規范路徑就是去掉相對路徑中的 . 和 .. 符號,得出一個絕對路徑。

      請注意,File 對象中傳入的相對路徑是相對于你當前 Java 文件所處的項目的根目錄而言的,而不是相對于當前 Java 文件的路徑。

      //比如目前的Java文件存儲在 E:\workspace\demo01 項目的 default 包下
      File f = new File(".\\path\\file.txt");
      System.out.println(f.getPath());           //獲取創建File對象時傳入的路徑  .\path\file3.txt
      System.out.println(f.getAbsolutePath());   //獲取絕對路徑   E:\workspace\demo01\.\path\file3.txt
      System.out.println(f.getCanonicalPath());  //獲取規范路徑  E:\workspace\demo01\path\file3.txt

       

      3、輸入字節流(InputStream)

      InputStream 就是 Java 標準庫提供的最基本的輸入流。它位于 java.io 這個包里。java.io 包提供了所有同步IO的功能。

      InputStream 并不是一個接口,而是一個抽象類,它是所有輸入流的超類。這個抽象類定義的一個最重要的方法就是 int read(),簽名如下:

      //該方法會讀取輸入流的下一個字節,并返回字節表示的int值(0~255,一個字節的十進制范圍就是0~255)。如果已讀到末尾,返回-1表示不能繼續讀取了。
      public abstract int read() throws IOException;

      read() 方法是阻塞(Blocking)的,在調用InputStreamread()方法讀取數據時,必須等到 read() 方法返回后才會繼續執行下一段代碼。

      3.1、讀取文件(文件輸入字節流 FileInputStream)

      FileInputStreamInputStream的一個子類。顧名思義,FileInputStream就是從文件流中讀取數據。下面的代碼演示了如何完整地讀取一個FileInputStream的所有字節:

      public void readFile() throws IOException {   //拋出IO異常
          InputStream input = null;
          try {
              input = new FileInputStream("src/readme.txt");
              int n;
              while ((n = input.read()) != -1) { // 利用while同時讀取并判斷
                  System.out.println(n);
              }
          } finally {   //在finally里保證InputStream一定能關閉
              if (input != null) { input.close(); }  //通過close()方法來關閉流
          }
      }

      在計算機中,類似文件、網絡端口這些資源,都是由操作系統統一管理的。應用程序在運行的過程中,如果打開了一個文件進行讀寫,完成后要及時地關閉,以便讓操作系統把資源釋放掉。否則,應用程序占用的資源會越來越多,不但白白占用內存,還會影響其他應用程序的運行。

      InputStreamOutputStream都是通過close()方法來關閉流。關閉流就會釋放對應的底層資源。

      在讀取或寫入IO流的過程中,可能會發生錯誤,例如,文件不存在導致無法讀取,沒有寫權限導致寫入失敗,等等,這些底層錯誤由Java虛擬機自動封裝成IOException異常并拋出。因此,所有與IO操作相關的代碼都必須正確處理IOException。我們可以在 finally 里面調用 close 來保證不管 InputStream 是否發生錯誤都能正常關閉。

       

      我們可以用Java 7引入的新的try(resource)的語法來讓編譯器自動關閉資源。只需要編寫try語句,編譯器就會自動查看看try(resource = ...)中的對象是否實現了java.lang.AutoCloseable接口,如果實現了,就自動加上finally語句并調用close()方法為我們關閉資源。

      public void readFile() throws IOException {
          try (InputStream input = new FileInputStream("src/readme.txt")) {
              int n;
              while ((n = input.read()) != -1) {
                  System.out.println(n);
              }
          } // 編譯器會在此自動為我們寫入finally并調用close()
      }

       

      3.2、利用緩沖區讀取文件

      在讀取流的時候,一次讀取一個字節并不是最高效的方法。很多流支持一次性讀取多個字節到緩沖區,對于文件和網絡流來說,利用緩沖區一次性讀取多個字節效率往往要高很多。InputStream提供了兩個重載方法來支持讀取多個字節:

      • int read(byte[] b):讀取若干字節并填充到byte[]數組,返回一次性讀取的字節數
      • int read(byte[] b, int off, int len):指定byte[]數組的偏移量和最大填充數

      利用上述方法一次讀取多個字節時,需要先定義一個byte[]數組作為緩沖區,read()方法會盡可能多地讀取字節到緩沖區, 但不會超過緩沖區的大小。read()方法的返回值不再是字節的int值,而是返回實際讀取了多少個字節。如果返回-1,表示沒有更多的數據了。

      public void readFile() throws IOException {
          try (InputStream input = new FileInputStream("src/readme.txt")) {
              // 定義1000個字節大小的緩沖區。(如果定義的緩沖區字節數組太小,則讀出來可能有亂碼。比如緩沖區是10個字節,一個中文是2-4個字節,一次性讀不完則可能只讀到某個中文的字節數的一半導致出現亂碼)
              byte[] buffer = new byte[1000];
              int n;
              while ((n = input.read(buffer)) != -1) { // 讀取到緩沖區
                  System.out.println("一次性讀取了" + n + "個字節");
                  System.out.println(new String(buffer, 0, n));   //輸出字符串
              }
          }
      }

       

      4、輸出字節流(OutputStream)

      OutputStream是Java標準庫提供的最基本的輸出流,OutputStream也是抽象類,它是所有輸出流的超類。這個抽象類定義的一個最重要的方法就是void write(int b)

      //該方法會根據參數的十進制的值表示的字節來寫入
      public abstract void write(int b) throws IOException;

      InputStream類似,OutputStream也提供了close()方法關閉輸出流,以便釋放系統資源。

      OutputStream還提供了一個flush()方法,該方法能將緩沖區的內容進行輸出。在緩沖區寫滿了時,OutputStream會自動調用該方法。在調用close()方法關閉OutputStream之前,也會自動調用flush()方法。當然,我們也可以主動去調用該方法。

      4.1、將字節寫入文件(文件輸出字節流 FileOutputStream)

      我們可以調用 write(int n) 方法來將十進制 n 代表的字節寫入某個文件當中。當該文件不存在時,該方法會自動創建一個文件并且寫入。當文件已經存在時,該方法會創建一個新的同名文件進行覆蓋并寫入。當目錄不存在時會報錯。

      public void writeFile() throws IOException {
          OutputStream output = new FileOutputStream("out/readme.txt");
          output.write(72); // H
          output.write(101); // e
          output.write(108); // l
          output.write(108); // l
          output.write(111); // o
          output.flush();  //write方法只是將數據寫到內存中,該方法會將內存中的數據寫到硬盤中。可以不手動調用該方法,因為在調用close()時也會自動調用flush()方法
          output.close();  
      }

      我們可以使用 write(byte[] arr)  方法來一次寫入多個字節:

      public void writeFile() throws IOException {
          try (OutputStream output = new FileOutputStream("out/readme.txt")) {
              output.write("Hello".getBytes("UTF-8")); 
              output.write("你好啊,你是哪位".getBytes("UTF-8"));
          } // 編譯器會自動在此為我們寫入finally并調用close()
      }

      InputStream的read()方法一樣,OutputStreamwrite()方法也是阻塞的,即必須等到這些方法返回后才會繼續執行下一段代碼。

      4.2、將某個文件的內容復制到另一個文件

      文件的字節流是非常通用的,因為字節流直接使用的是二進制。文件的字節流不僅可以用來操作文檔,還可以用來操作任何的其他類型的文件比如圖片、壓縮包等等。所以下面的方法對于其他類型的文件也是通用的,將路徑和文件名修改即可。

      File fileIN = new File("d:/TEST/MyFile2.txt"); //定義輸入文件
      File fileOUT = new File("d:/TEST/MyFile3.txt"); //定義輸出文件
         
      FileInputStream fis = null;
      FileOutputStream fos = null;
         
      try {    
         fis = new FileInputStream(fileIN); //輸入流連接到輸入文件
         fos = new FileOutputStream(fileOUT); //輸出流連接到輸出文件
          
         byte[] arr = new byte[10]; //該數組用來存入從輸入文件中讀取到的數據
         int len; //變量len用來存儲每次讀取數據后的返回值    
         while( ( len=fis.read(arr) ) != -1 ) {
            fos.write(arr, 0, len);
         }//while循環:每次從輸入文件讀取數據后,都寫入到輸出文件中
      } catch (IOException e) { e.printStackTrace(); } //關閉流 try { fis.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); }

       

      5、輸入字符流(Reader)

      Reader是Java的IO庫提供的另一個輸入流接口,他以字符 char 為單位進行讀取。

      字節輸入流InputStream和字符輸入流Reader的區別:

       

      java.io.Reader是所有字符輸入流的超類,它最主要的方法是 read(),該方法讀取字符流的下一個字符,并返回字符表示的int,范圍是0~65535。如果已讀到末尾,則返回-1。

      public int read() throws IOException;

      (讀取文本文件通常使用字符流,而像視頻、圖片、音頻等文件都是二進制數據,需要使用字節流讀取。當然文本文件也是可以通過字節流來讀取和寫入的。字節流更通用,字符流只不過是對字節流進行了封裝,查表操作)

       

      5.1、文件輸入字符流(FileReader)

      FileReaderReader的一個子類,它可以打開文件并獲取Reader。

      下面代碼示例一個一個字符讀取文件:

      public void readFile() throws IOException {
          // 創建一個FileReader對象:
          Reader reader = new FileReader("src/readme.txt");
          for (;;) {
              int n = reader.read(); // 反復調用read()方法,直到返回-1
              if (n == -1) {  //n為-1表示已經讀到末尾
                  break;
              }
              System.out.println((char)n); // 分別打印出讀取出的單個字符
          }
          reader.close(); // 關閉流
      }

       

      Reader還提供了一次性讀取若干字符并填充到char[]數組的方法:read(char[] c),此時它返回的是一次實際讀入的字符個數,最大不能超過char[] c字符數組的長度

      public int read(char[] c) throws IOException   //該方法返回的是一次實際讀入的字符個數,最大不會超過char[]數組的長度。返回-1表示流結束。

      使用char[]數組進行讀取:

      try {
          Reader reader = new FileReader("./test.txt");
          char[] buffer = new char[10];
          int n;
          while ((n = reader.read(buffer)) != -1) {   //此時會一次讀取10個字符,直到讀取完畢時會返回-1
              System.out.println("read " + n + " chars.");
              System.out.println(new String(buffer, 0, n));
          }
          reader.close();
      } catch (Exception e) {
          e.printStackTrace();
      }

      FileReader是默認按中文系統的 GBK 來編碼的,所以在讀取UTF-8文件時可能會出現亂碼情況,因為在 UTF-8 -> GBK -> UTF-8 的過程中編碼會出現損失從而造成結果不能還原成最初的字符。

      為了避免讀出來是亂碼,我們可以在創建FileReader時指定編碼。(注意:FileReader 構造函數帶編碼是在 Java 11 中加入,即JDK11以下的版本不支持。在低版本 JDK 中如果需要指定編碼讀取文件,我們可以使用 InputStreamReader 來讀取文件,該類的構造函數可以指定編碼格式)

      public void readFile() throws IOException {
          try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) {
              char[] buffer = new char[1000];
              int n;
              while ((n = reader.read(buffer)) != -1) {
                  System.out.println("read " + n + " chars.");
              }
          }
      }

       

      5.2、字節流轉成字符流(InputStreamReader,可指定讀取時使用的編碼格式)

      大部分的字符流 Reader 實際上是基于字節流 InputStream 構造的,因為Reader需要從InputStream中讀入字節流(byte),然后,根據編碼設置,再轉換為char就可以實現字符流。如果我們查看FileReader的源碼,它在內部實際上持有一個FileInputStream

      InputStreamReader就可以把任何InputStream轉換為ReaderInputStreamReader 是字符流Reader的子類,是字節流通向字符流的橋梁。 該類讀取字節,并使用指定的字符集(編碼格式)將其解碼為字符。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。

      你可以在構造器重指定編碼的方式,如果不指定的話將采用底層操作系統的默認編碼方式,例如 GBK 等。

      構造方法如下:

      參數:InputStream in  字節輸入流,用來讀取文件中保存的字節,String charsetName  指定的編碼表名稱,不區分大小寫,可以是utf-8/UTF-8,gbk/GBK,...不指定默認使用UTF-8

      InputStreamReader(InputStream in)   //創建一個使用默認字符集的 InputStreamReader。
      InputStreamReader(InputStream in, String charsetName)   //創建使用指定字符集的 InputStreamReader。

      該類繼承于 Reader 類,繼承了父類的共性成員方法:

      int read()   //讀取單個字符并返回。
      int read(char[] cbuf)    //一次讀取多個字符,將字符讀入數組。
      void close()     //關閉該流并釋放與之關聯的所有資源。

       

      使用InputStreamReader讀取文件代碼示例如下:

      先創建一個InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱。然后使用InputStreamReader對象中的方法read讀取文件,最后釋放資源。注意:構造方法中指定的編碼表名稱要和文件的編碼相同,否則會發生亂碼

      public static void main(String[] args) throws IOException {
          //創建一個字節流FileInputStream
          InputStream input = new FileInputStream("./readme.txt");
          //創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱。InputStreamReader將會將字節流按照UTF-8進行解碼為字符流
          Reader reader = new InputStreamReader(input, "UTF-8");
      
          //使用InputStreamReader對象中的方法read讀取文件
          int len = 0;
          while ((len = reader.read()) != -1) {
              System.out.println((char) len);   //分別打印出讀取的單個字符
          }
          // 3.釋放資源
          reader.close();
      }

       

      5.3、按行讀取文本文件(BufferedReader)

      BufferedReader 是緩沖字符輸入流。它繼承于Reader。BufferedReader 的作用是為其他字符輸入流添加一些緩沖功能。

      java.io.BufferedReader和java.io.BufferedWriter類各擁有8192字符的緩沖區。當BufferedReader在讀取文本文件時,會先盡量從文件中讀入字符數據并置入緩沖區,而之后若使用read()方法,會先從緩沖區中進行讀取。如果緩沖區數據不足,才會再從文件中讀取,使用BufferedWriter時,寫入的數據并不會先輸出到目的地,而是先存儲至緩沖區中。如果緩沖區中的數據滿了,才會一次對目的地進行寫出。

      構造方法:

      BufferedReader br = new BufferReader(Reader in);  //Reader in是輸入字符流

      主要方法有:

      int read();//讀取單個字符。
      int read(char[] cbuf,int off,int len);  //將字符讀入到數組的某一部分。返回讀取的字符數。達到尾部 ,返回-1。
      
      String readLine();      //讀取文本的一行內容

      BufferedReader 的 readLine() 方法使用起來特別方便,每次讀回來的都是一行,避免了需要手動拼接字符串的繁瑣

      使用BufferedReader讀取文件代碼示例:

      import java.io.BufferedReader;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStreamReader;
       
      public class Main 
      {
          public static void main(String[] args) throws IOException{
              //BufferedReader可以按行讀取文件
              FileInputStream inputStream = new FileInputStream("d://a.txt");
              BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));  //可以在構造InputStreamReader類時指定使用UTF-8來讀取以避免出現亂碼情況
                  
              String str = null;
              while((str = bufferedReader.readLine()) != null){
                  System.out.println(str);
              }
                  
              //close
              inputStream.close();
              bufferedReader.close();
          }
      }

       

      6、輸出字符流(Writer)

      Writer就是帶編碼轉換器的OutputStream,它把char轉換為byte并輸出。

      Writer是所有字符輸出流的超類,它提供的方法主要有:

      • 寫入一個字符(0~65535):void write(int c)
      • 寫入字符數組的所有字符:void write(char[] c)
      • 寫入String表示的所有字符:void write(String s)

       

      6.1、文件輸出字符流(FileWriter)

      FileWriter就是向文件中寫入字符流的Writer。它的使用方法和FileReader類似:

      try {
          Writer writer = new FileWriter("./readme.txt");
          writer.write('H'); // 寫入單個字符
          writer.write("Hello".toCharArray()); // 寫入char[]
          writer.write("你好啊hello~"); // 直接寫入String
      
          writer.flush();  //可不寫
          writer.close();
      } catch (Exception e) {
          e.printStackTrace();
      }

       

      6.2、字節流轉成字符流(OutputStreamWriter,可指定輸出時的編碼)

      大部分的 Writer 實際上是基于OutputStream構造的,它接收char,然后在內部自動轉換成一個或多個byte,并寫入OutputStreamOutputStreamWriter就是一個將任意的OutputStream轉換為Writer的轉換器。

      構造方法:參數:OutputStream out:字節輸出流,可以用來寫轉換之后的字節到文件中,String charsetName:指定的編碼表名稱,不區分大小寫,可以是utf-8/UTF-8,gbk/GBK,...不指定將默認使用UTF-8

      OutputStreamWriter(OutputStream out)   //創建使用默認字符編碼的 OutputStreamWriter。
      OutputStreamWriter(OutputStream out, String charsetName)  //創建使用指定字符集的 OutputStreamWriter。

      該類繼承 Writer 類,繼承了父類的共性成員方法

      void write(int c)        //寫入單個字符。
      void write(char[] cbuf)  //寫入字符數組。
      abstract  void write(char[] cbuf, int off, int len)  //寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。
      void write(String str)  //寫入字符串。
      void write(String str, int off, int len)   //寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。
      void flush()   //刷新該流的緩沖。
      void close()   //關閉此流,但要先刷新它。 

       

      使用 OutputStreamWriter 輸出字符代碼示例:

      public static void main(String[] args) throws IOException {
          //1.創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱
          //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\utf_8.txt"),"utf-8");   //可指定編碼格式
          OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\utf_8.txt"));//不指定將默認使用UTF-8
      //2.使用OutputStreamWriter對象中的方法write,把字符轉換為字節存儲緩沖區中(編碼) osw.write("你好");
      //3.使用OutputStreamWriter對象中的方法flush,把內存緩沖區中的字節刷新到文件中(使用字節流寫字節的過程) osw.flush(); //4.釋放資源 osw.close(); }

       

      6.3、BufferedWriter

      BufferedReader和BufferedWriter都是帶有默認緩沖區的字符輸入輸出流,其效率相較于沒有緩沖區要高。使用BufferedWriter時,寫入的數據并不會先輸出到目的地,而是先存儲至緩沖區中。如果緩沖區中的數據滿了,才會一次對目的地進行寫出。

      BufferedWriter通過字符數組來緩沖數據,當緩沖區滿或者用戶調用flush()函數時,它就會將緩沖區的數據寫入到輸出流中。

      構造方法:

      bufferedWriter bf = new bufferedWriter(Writer out );  //Writer out是輸出的字符流

      主要方法:

      void write(char ch);//寫入單個字符。
      void write(char []cbuf,int off,int len) //寫入字符數據的某一部分。
      void write(String s,int off,int len)    /寫入字符串的某一部分。
      void newLine()  //寫入一個行分隔符。
      void flush();   //刷新該流中的緩沖。將緩沖數據寫到目的文件中去。
      void close();   //關閉此流,再關閉前會先刷新他。

      使用BufferWriter往文件輸出內容代碼示例:

      public static void outMsg(String msg, boolean flag, String filename) {
          try {
              File file = new File(filename);
              OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(file, flag), "UTF-8");  //可以在聲明FileOutputStreamWriter時指定編碼
              BufferedWriter writer = new BufferedWriter(write);  //聲明BufferedWriter時需傳入字符輸入流
              writer.write(msg);
              writer.flush();
              writer.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }

       

       

      9、SXSSWorkbook和XSSWorkbook

      在日常開發使用中,我們建議使用SXSSWorkbook,應禁止使用 XSSWorkbook。

      SXSSWorkbook和 XSSWorkbook 都是 Apache POI 庫中用于操作 Excel 2007+(.xlsx 格式)的類,但它們的設計目標和內存使用策略有很大差異,尤其在處理大型 Excel 文件時表現截然不同。

      特性XSSWorkbookSXSSWorkbook
      內存占用 高(全量加載到內存) 低(超出閾值后寫入臨時文件)
      設計目標 適用于中小型 Excel 文件 專門優化大型 Excel 文件(十萬行級以上)
      功能完整性 支持所有 Excel 操作(讀寫、樣式、公式等) 功能有限制(如不支持公式求值、部分樣式)
      臨時文件 不生成 會生成臨時文件,需手動清理

       

       9.1、XSSWorkbook

      • 工作原理:將整個 Excel 文件的所有工作表、行、單元格等信息全部加載到內存中,適合對 Excel 進行復雜操作(如修改樣式、計算公式、合并單元格等)。
      • 優點:功能完整,支持 Excel 的所有特性,API 易用。
      • 缺點:處理大型文件時會占用大量內存,容易引發 OutOfMemoryError(OOM)。例如,生成 10 萬行數據的 Excel 可能需要數百 MB 內存。
      • 適用場景:中小型 Excel 文件(行數較少,通常幾萬行以內),或需要復雜格式處理的場景。
      // XSSWorkbook 示例(處理小型文件)
      try (XSSFWorkbook workbook = new XSSFWorkbook();
           FileOutputStream fos = new FileOutputStream("small_file.xlsx")) {
          XSSFSheet sheet = workbook.createSheet("數據");
          
          // 寫入 1000 行數據(內存可承受)
          for (int i = 0; i < 1000; i++) {
              XSSFRow row = sheet.createRow(i);
              row.createCell(0).setCellValue("行 " + i);
          }
          workbook.write(fos);
      } catch (IOException e) {
          e.printStackTrace();
      }

       

      9.2、SXSSWorkbook 

      • 工作原理:SXSSWorkbook 是 XSSWorkbook 的流式擴展,通過設置內存閾值(如 100 行),當行數超過閾值時,會將超出的行寫入臨時文件(默認在系統臨時目錄),只在內存中保留最近的 N 行數據。
      • 優點:內存占用極低,可處理百萬級甚至千萬級行數據,避免 OOM。
      • 缺點:
        • 功能受限:不支持公式求值、圖表、數據透視表等復雜功能,部分樣式設置有限制。
        • 生成臨時文件:需手動調用 dispose() 方法清理臨時文件,否則可能占用磁盤空間。
        • 不支持隨機訪問:寫入后無法再修改已刷新到臨時文件的行(只能修改內存中保留的行)。
      • 適用場景:生成超大型 Excel 文件(如數據導出、報表生成),且對格式要求不復雜的場景。
      // SXSSWorkbook 示例(處理大型文件)
      try (SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 內存中保留 100 行,超出寫入臨時文件
           FileOutputStream fos = new FileOutputStream("large_file.xlsx")) {
          SXSSFSheet sheet = workbook.createSheet("大數據");
          
          // 寫入 100 萬行數據(內存占用可控)
          for (int i = 0; i < 1_000_000; i++) {
              SXSSFRow row = sheet.createRow(i);
              row.createCell(0).setCellValue("行 " + i);
          }
          
          workbook.write(fos);
          workbook.dispose(); // 清理臨時文件(關鍵!)
      } catch (IOException e) {
          e.printStackTrace();
      }

      SXSSWorkbook 必須調用 dispose() 方法,否則臨時文件會殘留(路徑可通過 workbook.setTempFileCreationStrategy() 自定義)。

       

      posted @ 2020-04-29 17:58  wenxuehai  閱讀(793)  評論(0)    收藏  舉報
      //右下角添加目錄
      主站蜘蛛池模板: 久久天天躁夜夜躁狠狠ds005| 四虎永久免费高清视频| 蜜臀一区二区三区精品免费 | 欧美午夜精品久久久久久浪潮| 成人无码一区二区三区网站| 黑人巨大亚洲一区二区久| 99re视频在线| 宾馆人妻4P互换视频| 亚洲区欧美区综合区自拍区| 久久69国产精品久久69软件| 涿州市| 国产中年熟女高潮大集合| 大香伊蕉在人线国产最新2005| 日本一区二区三本视频在线观看| 人妻少妇偷人精品一区| 色综合久久中文综合网| 天堂网av一区二区三区| 亚洲大尺度视频在线播放| 亚洲人亚洲人成电影网站色| 天堂…中文在线最新版在线| 办公室强奷漂亮少妇视频| 精品国产高清中文字幕| 精品国产精品三级精品av网址| 九九热在线观看视频精品| 国产精品午夜精品福利| 好吊妞无缓冲视频观看| 日韩一区二区三区无码a片| 日韩精品中文字幕人妻| 精品无码日韩国产不卡av| 精品久久久久久国产| 亚洲精品韩国一区二区| 色欲狠狠躁天天躁无码中文字幕| 久久天天躁狠狠躁夜夜婷| 色悠悠久久精品综合视频| 国产av最新一区二区| 国产亚洲精品自在久久vr| 久久精品夜色噜噜亚洲av| 中文字幕一区二区三区久久蜜桃| 精品无码人妻一区二区三区| 精品国产综合一区二区三区| 日本无翼乌邪恶大全彩h|