<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          死磕 IO 流?你都磕對地方了么

          共 22180字,需瀏覽 45分鐘

           ·

          2021-04-21 18:25

          微信搜一搜
          村雨遙

          前言

          我們?nèi)粘i_發(fā)過程中,有許多方面都涉及到 IO 流,比如上傳下載、傳輸、設(shè)計模式等等。而所有的一切都是基于 IO 流來進行,所以今天就來看看 Java 中 IO 流的相關(guān)知識點。

          本文主要內(nèi)容安排如下:

          • 文件對象
          • 流簡介
          • 字節(jié)流
          • 字符流

          文件對象

          文件路徑

          Java 標準庫 java.io 提供了 File 對象用于操作文件和目錄,也就是說我們的文件和目錄都是可以通過 File 封裝成對象的。構(gòu)造 File 對象時,需要傳入我們的文件或目錄的路徑名,常用的構(gòu)造方法如下:

          方法描述
          File(String pathName)通過將給定路徑名字符串轉(zhuǎn)換為抽象路徑名來創(chuàng)建新實例
          File(String parent, String child)從父路徑名字符串和子路徑名字符串創(chuàng)建新實例
          File(File parent, String child)從父抽象路徑名和子路徑名字符串創(chuàng)建新實例
          import java.io.File;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : FileObject
           * @date : 2021/4/20 9:20
           * @description : 創(chuàng)建 File 對象的三個構(gòu)造方法
           */


          public class FileObject {
              public static void main(String[] args) {

                  File file1 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/1.txt");
                  System.out.println(file1);

                  File file2 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data""1.txt");
                  System.out.println(file2);

                  File file3 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data");
                  File file4 = new File(file3, "1.txt");
                  System.out.println(file4);
              }
          }

          對于我們傳入文件的路徑,既可以使用絕對路徑,也可以使用相對路徑。

          • 相對路徑:以當前文件所在位置為參考,然后建立出另一個文件所在位置路徑。我們最常用的有 ...,前者表示當前目錄,而后者則表示當前目錄的上一級目錄。假設(shè)我們當前目錄為 /home/cunyu1943/data,則 . 仍然表示該目錄,而 .. 則表示 /home/cunyu1943 目錄。
          • 絕對路徑:又可以分為 本地絕對路徑網(wǎng)絡(luò)絕對路徑。本地絕對路徑以根目錄為參考,指文件在硬盤中真實存在的路徑,比如在 Windows 系統(tǒng),我們的一個絕對路徑是 D:\\Softwares\\Typora\\Typora.exe,而在類 Unix 系統(tǒng)中則為 /home/cunyu1943/IO.md,此時需要注意平臺間的分隔符是不一樣的,但為了同一,推薦同一寫成 /,這樣程序在不同系統(tǒng)中遷移時也不會出現(xiàn)問題。而網(wǎng)絡(luò)絕對位置則指帶有網(wǎng)址的路徑,比如 https://cunyu1943.site/index.html
          import java.io.File;
          import java.io.IOException;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : FilePath
           * @date : 2021/4/20 9:55
           * @description : 文件路徑
           */


          public class FilePath {
              public static void main(String[] args) throws IOException {
                  File file = new File("../data/1.txt");
                  System.out.println(file.getPath());
                  System.out.println(file.getAbsolutePath());
                  System.out.println(file.getCanonicalPath());
              }
          }

          文件和目錄操作

          創(chuàng)建與刪除

          既然拿到了 File 對象,接下來就是通過操作該對象來進行創(chuàng)建和刪除文件或目錄了,以下是一些 File 類常用的創(chuàng)建和刪除方法。

          返回值方法描述
          booleancreateNewFile()當具有該名稱的文件不存在時,創(chuàng)建一個由該抽象路徑名命名的新空文件;存在時,則創(chuàng)建失敗
          booleanmkdir()創(chuàng)建由此抽象路徑名命名的目錄
          booleanmkdirs()創(chuàng)建由此抽象路徑名命名的多級目錄,包括任何必需但不存在的父目錄
          booleandelete()刪除由此抽象路徑名命名的文件或目錄,刪除目錄的前提是該目錄必須為空
          import java.io.File;
          import java.io.IOException;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : CreateAndDelete
           * @date : 2021/4/20 10:40
           * @description : 創(chuàng)建&刪除
           */


          public class CreateAndDelete {
              public static void main(String[] args) throws IOException {
                  File file1 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
                  if (file1.createNewFile()) {
                      System.out.println("創(chuàng)建文件成功");
                  } else {
                      System.out.println("創(chuàng)建文件失敗");
                  }

                  if (file1.delete()) {
                      System.out.println("刪除文件成功");
                  } else {
                      System.out.println("刪除文件失敗");
                  }

                  File file2 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/demo");
                  if (file2.mkdir()) {
                      System.out.println("創(chuàng)建文件夾成功");
                  } else {
                      System.out.println("創(chuàng)建文件夾失敗");
                  }

                  File file3 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/JavaSE/demo");
                  if (file3.mkdirs()) {
                      System.out.println("創(chuàng)建多級目錄成功");
                  } else {
                      System.out.println("創(chuàng)建多級目錄失敗");
                  }
              }
          }

          注意

          • 創(chuàng)建文件時,調(diào)用的是 createNewFile() 方法,而創(chuàng)建目錄時調(diào)用的是 mkdir() 或者 mkdirs() 方法。我們在調(diào)用時要注意區(qū)分,否則就算你的路徑是文件,當調(diào)用了創(chuàng)建目錄的方法后它也會創(chuàng)建成目錄而非文件。對應(yīng)的,就算你給定的路徑是目錄,當調(diào)用創(chuàng)建文件的方法后它也會創(chuàng)建成文件而非目錄。

          • 刪除目錄時,若目錄中有內(nèi)容(目錄、文件),則 不能直接刪除,而是應(yīng)該先刪除目錄中的內(nèi)容,然后才能刪除目錄;

          相關(guān)屬性

          獲取到 File 對象后,我們可以對其相關(guān)屬性進行判斷,常用方法如下:

          返回值方法描述
          longlength()該抽象路徑名表示的文件的所占字節(jié)大小
          booleancanRead()該抽象路徑名表示的文件是否可讀
          booleancanWrite()該抽象路徑名表示的文件是否可寫
          booleancanExecute()該抽象路徑名表示的文件是否可執(zhí)行
          import java.io.File;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : Main
           * @date : 2021/4/20 11:04
           * @description : 相關(guān)屬性
           */


          public class Main {
              public static void main(String[] args) {
                  File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/new.txt");

                  if (file.canExecute()) {
                      System.out.println("該對象可執(zhí)行");
                  } else {
                      System.out.println("該對象不可執(zhí)行");
                  }
                  if (file.canRead()) {
                      System.out.println("該對象可讀");
                  } else {
                      System.out.println("該對象不可讀");
                  }
                  if (file.canWrite()) {
                      System.out.println("該對象可寫");
                  } else {
                      System.out.println("該對象不可寫");
                  }

                  System.out.println("文件大小:" + file.length() + " Byte");
              }
          }

          判斷和獲取

          獲取到 File 對象后,我們既可以用它來表示文件,也可以用來表示目錄。而對于文件和目錄的判斷和獲取功能,可以使用如下常用的方法:

          返回值方法描述
          booleanisFile()測試此抽象路徑名表示的文件是否為普通文件
          booleanisDirectory()測試此抽象路徑名表示的文件是否為目錄
          booleanexists()測試此抽象路徑名表示的文件或目錄是否存在
          StringgetPath()將抽象路徑轉(zhuǎn)換為路徑字符串
          StringgetAbsolutePath()返回此抽象路徑名的絕對路徑名字符串
          StringgetName()返回由此抽象路徑名表示的文件或目錄的名稱
          String[]list()返回字符串數(shù)組,表示該抽象路徑名表示目錄下的文件和目錄
          File[]listFiles()返回抽象路徑名數(shù)組,表示該抽象路徑名表示目錄下的文件
          import java.io.File;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : Main
           * @date : 2021/4/20 11:15
           * @description : 判斷和獲取
           */


          public class Main {
              public static void main(String[] args) {
                  File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data");
                  System.out.println(file.isDirectory());
                  System.out.println(file.isFile());
                  System.out.println(file.exists());
                  System.out.println("-------------------------");
                  System.out.println(file.getPath());
                  System.out.println(file.getAbsolutePath());
                  System.out.println(file.getName());
                  System.out.println("-------------------------");
                  System.out.println("目錄下的文件和目錄列表:(文件或目錄名)");
                  for (String path : file.list()) {
                      System.out.println(path);
                  }
                  System.out.println("-------------------------");
                  System.out.println("目錄下的文件和目錄列表:(完整絕對路徑)");
                  for (File path : file.listFiles()) {
                      System.out.println(path);
                  }
              }
          }

          練習

          假設(shè)我們要遍歷 Windows 下 C 盤的 Windows 目錄,并且列出其中文件名和文件大小,而不用列出目錄名,我們可以利用如下代碼來實現(xiàn):

          import java.io.File;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : Test
           * @date : 2021/4/20 11:40
           * @description : 遍歷 C 盤 Windows 目錄下的文件,并打印文件名和大小
           */


          public class Test {
              public static void main(String[] args) {
                  File file = new File("C:/windows");
                  for (File item : file.listFiles()) {
                      if (item.isFile()) {
                          System.out.println("文件名:" + item.getName() + "\t文件大小占:" + item.length() + " 字節(jié)");
                      }
                  }
              }
          }

          什么是流

          所謂流,就是一系列數(shù)據(jù)的組合。當我們需要進行數(shù)據(jù)交互的時候,比如在服務(wù)器和客戶端之間進行數(shù)據(jù)交互時,我們此時就可以使用 Java 中的流來實現(xiàn)。Java 中,數(shù)據(jù)的輸入和輸出都是以流的形式來進行的。根據(jù)數(shù)據(jù)流方向的不同,我們可以將其分為:輸入流輸出流。而根據(jù)處理的數(shù)據(jù)單位不同,可分為:字節(jié)流字符流。兩者的關(guān)系可以描述為下表:


          字節(jié)流字符流
          輸入流InputStreamReader
          輸出流OutputStreamWriter

          而對于字節(jié)流和字符流的選用原則,我們建議遵循如下規(guī)則:如果數(shù)據(jù)能夠通過 Windows 自帶筆記本軟件打開并且能夠讀懂其中的內(nèi)容,則選用字符流,否則選擇字節(jié)流。而如果我們也不知道應(yīng)該使用何種類型的流,則默認使用字節(jié)流

          下圖描述了字節(jié)流和字符流的類層次圖,注意:無論是字節(jié)流還是字符流,其子類名都是以其父類名作為子類名的后綴的

          IO 流.png

          InputStream

          InputStream.png

          注意,InputStream 并非是并不是一個接口,而是所有字節(jié)輸入流所有類的父類。下面我們主要以 FileInputStream 來舉例,所謂 FileInputStream,就是從文件流中讀取數(shù)據(jù),然后將數(shù)據(jù)從文件中讀取到內(nèi)存,常用方法如下:

          返回值方法描述
          intavailable()返回該輸入流中可以讀取的字節(jié)數(shù)的估計值
          voidclose()關(guān)閉輸入流并釋放相關(guān)資源
          intread(bytep[] b)從輸入流讀取一些字節(jié)數(shù),并將其存儲到緩沖區(qū) b

          下面是一個從文件中讀取數(shù)據(jù)到內(nèi)存中的實例,文件內(nèi)容如下:

          import java.io.File;
          import java.io.FileInputStream;
          import java.io.IOException;
          import java.io.InputStream;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : TestInputStream
           * @date : 2021/4/20 15:29
           * @description : InputStream 實例
           */


          public class TestInputStream {

              public static void main(String[] args) {

                  String result = null;
                  File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/1.txt");
                  try (InputStream inputStream = new FileInputStream(file)) {

          //            讀取輸入流中可以被讀的 bytes 估計值
                      int size = inputStream.available();
          //            根據(jù) bytes 數(shù)創(chuàng)建數(shù)組
                      byte[] array = new byte[size];
          //            數(shù)據(jù)讀取到數(shù)組
                      inputStream.read(array);
          //            數(shù)組轉(zhuǎn)化為字符串
                      result = new String(array);

                  } catch (IOException e) {
                      e.printStackTrace();
                  }

          //        打印字符串
                  System.out.println(result);

              }
          }

          OutputStream

          OutputStream.png

          OutputStream 并非是并不是一個接口,而是所有輸出字節(jié)流的所有類的父類。下面我們主要以 FileOutputStream 來舉例,所謂 FileOutputStream,就是從內(nèi)存中讀取數(shù)據(jù),然后將數(shù)據(jù)從內(nèi)存存放到文件中,常用方法如下:

          返回值方法描述
          voidwrite(byte[] b)b.length 個字節(jié)從指定字節(jié)數(shù)組寫入此文件輸出流
          voidclose()關(guān)閉文件輸出流并釋放相關(guān)資源
          import java.io.*;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : TestOutputStream
           * @date : 2021/4/20 15:58
           * @description : OutputStream 實例
           */


          public class TestOutputStream {
              public static void main(String[] args) {
                  File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
                  String content = "這是一個 OutputStream 實例!";
                  try (OutputStream outputStream = new FileOutputStream(file)) {
          //            字符串轉(zhuǎn)換為 byte 數(shù)組
                      byte[] array = content.getBytes();

          //            寫入數(shù)據(jù)
                      outputStream.write(array);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }

                  System.out.println("寫入成功");
              }
          }

          需要注意的點:

          • 字節(jié)流寫入數(shù)據(jù)時如何實現(xiàn)換行?

          寫入換行的轉(zhuǎn)義字符的字節(jié)數(shù)組即可,但是需要注意,不同系統(tǒng)下?lián)Q行的轉(zhuǎn)義字符不同,Windows 下為 \r\n,macOS 下為 \r,而 Linux 下為 \m

          • 字節(jié)流寫入數(shù)據(jù)時如何實現(xiàn)追加?

          調(diào)用 public FileOutputStream(String name, boolean append) 這個構(gòu)造方法即可,當 appendtrue 時,表示追加,默認情況下是 false,表示不追加。

          字符串中的編解碼問題

          編碼

          • byte[] getBytes():使用平臺默認字符集將該字符串編碼成一系列字節(jié),然后將結(jié)果存儲到新的字節(jié)數(shù)組中;
          • byte[] getBytes(String charsetName):使用指定字符集將該字符串編碼為一系列字節(jié),然后將結(jié)果存儲到新的字節(jié)數(shù)組中;

          解碼

          • String(byte[] bytes):使用平臺默認字符集解碼指定的字節(jié)數(shù)來構(gòu)造新的字符串;
          • String(byte[] bytes, String charsetName):通過指定的字符集解碼指定的字節(jié)數(shù)組來構(gòu)造新的字符串;
          import java.io.UnsupportedEncodingException;
          import java.util.Arrays;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : EncodeAndDecode
           * @date : 2021/4/21 9:37
           * @description : 編碼和解碼
           */


          public class EncodeAndDecode {
              public static void main(String[] args) throws UnsupportedEncodingException {
          //        編碼
                  String str = "村雨遙";
                  byte[] bytes1 = str.getBytes();
                  byte[] bytes2 = str.getBytes("UTF-8");
                  byte[] bytes3 = str.getBytes("GBK");

                  System.out.println(Arrays.toString(bytes1));
                  System.out.println(Arrays.toString(bytes2));
                  System.out.println(Arrays.toString(bytes3));

          //        解碼
                  String res1 = new String(bytes1);
                  String res2 = new String(bytes1, "UTF-8");
                  String res3 = new String(bytes1, "GBK");

                  System.out.println(res1);
                  System.out.println(res2);
                  System.out.println(res3);
              }
          }

          Writer

          Writer.png

          當我們要寫入基于字符的數(shù)據(jù)到數(shù)據(jù)源中時,需要使用寫入器 Writer. 以其中的 FileWriter 具體展開,其常用方法如下:

          返回值方法描述
          voidclose()先刷新再關(guān)閉流,不能再寫數(shù)據(jù)
          voidflush()刷新流,可以繼續(xù)寫數(shù)據(jù)
          voidnewLine()寫入行分隔符
          voidwrite()寫入字符或字符串
          import java.io.BufferedWriter;
          import java.io.File;
          import java.io.FileWriter;
          import java.io.IOException;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : TestWriter
           * @date : 2021/4/20 18:35
           * @description : Writer 實例
           */


          public class TestWriter {
              public static void main(String[] args) {
                  File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
                  try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
                      bufferedWriter.write("公眾號:村雨遙");
                      bufferedWriter.newLine();
                      bufferedWriter.write("Blog:https://cunyu1943.site");
                      bufferedWriter.newLine();
                      bufferedWriter.flush();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
                  System.out.println("寫入成功");
              }
          }

          Reader

          Reader.png

          當我們要從數(shù)據(jù)源讀取基于字符的數(shù)據(jù)時,需要使用讀取器 Reader. 我們以 FileReader 實踐,其常用的方法有:

          返回值方法描述
          voidclose()關(guān)閉流并釋放相關(guān)資源
          intread()讀取一個字符
          StringreadLine()讀一行文字
          booleanready()獲取該流是否準備好被讀取

          我們以從文件中讀取內(nèi)容為例:

          import java.io.*;

          /**
           * @author : cunyu
           * @version : 1.0
           * @className : TestReader
           * @date : 2021/4/20 18:40
           * @description : Reader 實例
           */


          public class TestReader {
              public static void main(String[] args) {
                  String content = null;
                  File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
                  System.out.println("內(nèi)容如下:");
                  try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
                      while ((content = bufferedReader.readLine()) != null) {
                          System.out.println(content);
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }

          總結(jié)

          好了,關(guān)于 IO 流的知識點到此就結(jié)束了,趕緊學起來!如果你覺得本文對你有所幫助,那就點贊關(guān)注一波吧!

          對于文中遺漏或者錯誤的知識點,歡迎大家評論留言,咱們評論區(qū)見!



          瀏覽 58
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜芽欧美成人 | 久久无码av | 丁香婷婷五月 | 国产一区二区色婷婷 | 鸥美一流毛片在线免费观看 |