日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java笔记整理六(File类,递归,字节流IO,字符流IO,流中的异常处理,属性集Properties,缓冲流,转换流,序列化,打印流)

發布時間:2023/12/15 java 24 豆豆

1.File類

java.io.File 類是文件和目錄路徑名的抽象表示,主要用于文件和目錄的創建、查找和刪除等操作。

文件和目錄路徑名的抽象表示

java把文件和文件夾封裝位為一個File類,我們可以用File類的對文件和文件夾進行操作

使用File類我們可以

  • 創建一個文件夾/文件
  • 刪除文件/文件夾
  • 獲取文件/文件夾
  • 判斷文件/文件夾是否存在
  • 獲取文件大小

File是一個與系統無關的類,任何系統都可以使用這個類中的方法。

重點:
file:文件
directory:目錄
path:路徑

static String pathSeparator:路徑分隔符
static char pathSeparator:路徑分隔符

Srting pathSeparator=File.pathSeparator; windows:分號 linux:冒號

static String separator:默認名稱分隔符
static char separator:默認名稱分隔符

Srting separator=File.separator; windows:\ linux:/

路徑不能寫死了
“c:“+File.separator+”develop“+File.separator+a.txt”

絕對路徑,相對路徑

絕對路徑:完整路徑c:\a.txt
相對路徑:簡化路徑,相對當前項目的根目錄

注意:

  • 路徑不區分大小寫
  • 路徑中文件名稱分隔符windows使用雙反斜杠
  • File中的構造方法

    • public File(String pathname) :通過將給定的路徑名字符串轉換為抽象路徑名來創建新的 File實例。
      可以是以文件/文件夾結尾。可以相對路徑也可以是絕對路徑,可以是存在的也可以不存在。創建File對象,只把字符串路徑封裝給File對象,不考慮路徑對象 它重寫了File的toString方法。

    • public File(String parent, String child) :從父路徑名字符串和子路徑名字符串創建新的 File實例。
      父路徑和子路徑,可以單獨書寫,使用靈活

    • public File(File parent, String child) :從父抽象路徑名和子路徑名字符串創建新的 File實例。
      父路徑和子路徑,可以單獨書寫,使用靈活,父路徑是File類型,可以使用File的方法對路徑進行一些操作,再使用路徑創建對象

    獲取功能的方法

    • public String getAbsolutePath() :返回此File的絕對路徑名字符串。

    • public String getPath() :將此File轉換為路徑名字符串。

    • public String getName() :返回由此File表示的文件或目錄的名稱。

    • public long length() :返回由此File表示的文件的長度。

      方法演示,代碼如下:

    public class FileGet {public static void main(String[] args) {File f = new File("d:/aaa/bbb.java"); System.out.println("文件絕對路徑:"+f.getAbsolutePath());System.out.println("文件構造路徑:"+f.getPath());System.out.println("文件名稱:"+f.getName());System.out.println("文件長度:"+f.length()+"字節");File f2 = new File("d:/aaa"); System.out.println("目錄絕對路徑:"+f2.getAbsolutePath());System.out.println("目錄構造路徑:"+f2.getPath());System.out.println("目錄名稱:"+f2.getName());System.out.println("目錄長度:"+f2.length());}}輸出結果:文件絕對路徑:d:\aaa\bbb.java文件構造路徑:d:\aaa\bbb.java文件名稱:bbb.java文件長度:636字節目錄絕對路徑:d:\aaa目錄構造路徑:d:\aaa目錄名稱:aaa目錄長度:4096

    判斷功能的方法

    • public boolean exists() :此File表示的文件或目錄是否實際存在。
    • public boolean isDirectory() :此File表示的是否為目錄。
    • public boolean isFile() :此File表示的是否為文件。

    方法演示,代碼如下:

    public class FileIs {public static void main(String[] args) {File f = new File("d:\\aaa\\bbb.java");File f2 = new File("d:\\aaa");// 判斷是否存在System.out.println("d:\\aaa\\bbb.java 是否存在:"+f.exists());System.out.println("d:\\aaa 是否存在:"+f2.exists());// 判斷是文件還是目錄System.out.println("d:\\aaa 文件?:"+f2.isFile());System.out.println("d:\\aaa 目錄?:"+f2.isDirectory());} } 輸出結果: d:\aaa\bbb.java 是否存在:true d:\aaa 是否存在:true d:\aaa 文件?:false d:\aaa 目錄?:true

    創建刪除功能的方法

    • public boolean createNewFile() :當且僅當具有該名稱的文件尚不存在時,創建一個新的空文件。 只能創建文件。不能創建文件夾。需要處理異常,必須路徑存在,否則會拋出io異常。

    • public boolean delete() :刪除由此File表示的文件或目錄。 不走回收站

    • 文件/文件夾刪除成功,返回true

    • 文件夾有內容不回刪除,返回false,構造方法中不存在也返回false

    • public boolean mkdir() :創建由此File表示的目錄。只能創建單集空文件夾
    • public boolean mkdirs() :創建由此File表示的目錄,包括任何必需但不存在的父目錄。可以創建單級文件夾也可以創建多級空文件夾。
    • 返回值:true:文件夾不存在,創建文件夾,返回true
      返回false:文件夾存在,不會創建,構造方法中給出的路徑不存在也返回false
      只能創建文件夾不能創建文件
      創建文件的路徑必須存在,否則會拋出異常

    方法演示,代碼如下:

    public class FileCreateDelete {public static void main(String[] args) throws IOException {// 文件的創建File f = new File("aaa.txt");System.out.println("是否存在:"+f.exists()); // falseSystem.out.println("是否創建:"+f.createNewFile()); // trueSystem.out.println("是否存在:"+f.exists()); // true// 目錄的創建File f2= new File("newDir"); System.out.println("是否存在:"+f2.exists());// falseSystem.out.println("是否創建:"+f2.mkdir()); // trueSystem.out.println("是否存在:"+f2.exists());// true// 創建多級目錄File f3= new File("newDira\\newDirb");System.out.println(f3.mkdir());// falseFile f4= new File("newDira\\newDirb");System.out.println(f4.mkdirs());// true// 文件的刪除System.out.println(f.delete());// true// 目錄的刪除System.out.println(f2.delete());// trueSystem.out.println(f4.delete());// false} }

    API中說明:delete方法,如果此File表示目錄,則目錄必須為空才能刪除。

    目錄的遍歷

    • public String[] list() :返回一個String數組,表示該File目錄中的所有子文件或目錄。把獲取到的多個名稱存儲到一個String類型的數組中。

    • public File[] listFiles() :返回一個File數組,表示該File目錄中的所有的子文件或目錄。遍歷構造方法中給出的目錄,獲取所有文件或文件夾的名稱,把獲取到的多個名稱存儲到一個String類型的數組中

    list和listFiles方法遍歷的是構造方法中給出的目錄
    如果走早方法中給出路徑不存在,會拋出空指針異常
    如果構造方法中給出的路徑不是一個目錄,會拋出空指針異常

    public class FileFor {public static void main(String[] args) {File dir = new File("d:\\java_code");//獲取當前目錄下的文件以及文件夾的名稱。String[] names = dir.list();for(String name : names){System.out.println(name);}//獲取當前目錄下的文件以及文件夾對象,只要拿到了文件對象,那么就可以獲取更多信息File[] files = dir.listFiles();for (File file : files) {System.out.println(file);}} }

    小貼士:

    調用listFiles方法的File對象,表示的必須是實際存在的目錄,否則返回null,無法進行遍歷。

    遞歸

    遞歸:指再當前方法體調用自己

    分為直接遞歸和間接遞歸
    注意事項:

    • 遞歸一定要有條件限制,保證遞歸能夠停止
    • 遞歸次數不能太多,否則可能會發生棧內存溢出
    • 構造方法禁止遞歸

    遞歸方法使用前提:
    當調用方法的時候,方法主體不變,每次調用方法的參數不同,可以使用遞歸

    使用遞歸計算1–n的和

    使用遞歸必須明確:

  • 遞歸的結束條件:獲取到一結束
  • 遞歸的目的:獲取下一個被加的數字
  • 實現代碼

    public class DiGuiDemo {public static void main(String[] args) {//計算1~num的和,使用遞歸完成int num = 5;// 調用求和的方法int sum = getSum(num);// 輸出結果System.out.println(sum);}/*通過遞歸算法實現.參數列表:int 返回值類型: int */public static int getSum(int num) {/* num為1時,方法返回1,相當于是方法的出口,num總有是1的情況*/if(num == 1){return 1;}/*num不為1時,方法返回 num +(num-1)的累和遞歸調用getSum方法*/return num + getSum(num-1);} }

    遞歸求階乘

    階乘:所有小于及等于該數的正整數的積。

    n的階乘:n! = n * (n-1) *...* 3 * 2 * 1 推理得出:n! = n * (n-1)!

    代碼實現

    public class DiGuiDemo {//計算n的階乘,使用遞歸完成public static void main(String[] args) {int n = 3;// 調用求階乘的方法int value = getValue(n);// 輸出結果System.out.println("階乘為:"+ value);}/*通過遞歸算法實現.參數列表:int 返回值類型: int */public static int getValue(int n) {// 1的階乘為1if (n == 1) {return 1;}/*n不為1時,方法返回 n! = n*(n-1)!遞歸調用getValue方法*/return n * getValue(n - 1);} }

    遞歸打印多級目錄

    分析:多級目錄的打印,就是當目錄的嵌套。遍歷之前,無從知道到底有多少級目錄,所以我們還是要使用遞歸實現。

    代碼實現

    public class DiGuiDemo2 {public static void main(String[] args) {// 創建File對象File dir = new File("D:\\aaa");// 調用打印目錄方法printDir(dir);}public static void printDir(File dir) {// 獲取子文件和目錄File[] files = dir.listFiles();// 循環打印/*判斷:當是文件時,打印絕對路徑.當是目錄時,繼續調用打印目錄的方法,形成遞歸調用.*/for (File file : files) {// 判斷if (file.isFile()) {// 是文件,輸出文件絕對路徑System.out.println("文件名:"+ file.getAbsolutePath());} else {// 是目錄,輸出目錄絕對路徑System.out.println("目錄:"+file.getAbsolutePath());// 繼續遍歷,調用printDir,形成遞歸printDir(file);}}} }

    文件搜索

    搜索D:\aaa 目錄中的.java 文件。

    分析

  • 目錄搜索,無法判斷多少級目錄,所以使用遞歸,遍歷所有目錄。
  • 遍歷目錄時,獲取的子文件,通過文件名稱,判斷是否符合條件。
  • 代碼實現

    public class DiGuiDemo3 {public static void main(String[] args) {// 創建File對象File dir = new File("D:\\aaa");// 調用打印目錄方法printDir(dir);}public static void printDir(File dir) {// 獲取子文件和目錄File[] files = dir.listFiles();// 循環打印for (File file : files) {if (file.isFile()) {// 是文件,判斷文件名并輸出文件絕對路徑if (file.getName().endsWith(".java")) {System.out.println("文件名:" + file.getAbsolutePath());}} else {// 是目錄,繼續遍歷,形成遞歸printDir(file);}}} }

    文件過濾器優化

    listFiles(FileFilter fileter)
    File類中有兩個和ListFiles重載的方法,方法參數就是過濾器

    java.io.FileFilter是一個接口,是File的過濾器。 該接口的對象可以傳遞給File類的
    用于抽象路徑名(File對象)的過濾器,用來過濾文件
    boolean accept(File pathname) :測試pathname是否應該包含在當前File目錄中,符合則返回true。

    listFiles(FilenameFilter fileter) :
    java.io.FilenameFilter接口:實現此接口的類實例可用于過濾器文件名
    用于過濾文件名稱
    boolean accept(File dir ,String name) :測試文件是否包含在某一文件夾中

    File dir:構造方法中傳遞的被遍歷的目錄
    String name::使用ListFiles方法遍歷目錄,獲取的每一個文件/文件夾的名稱

    注意:兩個過濾器接口是沒有實現類的,需要我們自己寫實現類,重寫過濾方法accep,在方法中自己定義過濾器規則。

    分析

  • 接口作為參數,需要傳遞子類對象,重寫其中方法。我們選擇匿名內部類方式,比較簡單。
  • accept方法,參數為File,表示當前File下所有的子文件和子目錄。保留住則返回true,過濾掉則返回false。保留規則:
  • 要么是.java文件。
  • 要么是目錄,用于繼續遍歷。
  • 通過過濾器的作用,listFiles(FileFilter)返回的數組元素中,子文件對象都是符合條件的,可以直接打印。
  • 代碼實現:

    public class DiGuiDemo4 {public static void main(String[] args) {File dir = new File("D:\\aaa");printDir2(dir);}public static void printDir2(File dir) {// 匿名內部類方式,創建過濾器子類對象File[] files = dir.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {return pathname.getName().endsWith(".java")||pathname.isDirectory();}});// 循環打印for (File file : files) {if (file.isFile()) {System.out.println("文件名:" + file.getAbsolutePath());} else {printDir2(file);}}} }

    FileFilter過濾器的原理和使用

    必須明確兩件事情:

  • 過濾器中accept方法是誰調用的,
  • accept方法的參數pathname是什么。
    ListFiles方法一共做了三件事情:
  • ListFiles方法對構造中傳遞的目錄進行遍歷,獲取目錄中的每一個文件夾/文件----封裝成File對象
  • ListFiles方法會調用參數傳遞的過濾器中的方法accept
  • listFiles方法會把遍歷的到的File對象,傳遞過accept方法的參數pathname
  • accept方法返回的是一個boolean值
    true: 會把傳遞過去的File對象保存到File數組中
    false:就不會把傳遞過去的File對象保存到File數組中

    因此,過濾的規則:
    在accept方法中,判斷File對象

    Lambda優化

    分析:FileFilter是只有一個方法的接口,因此可以用lambda表達式簡寫。

    lambda格式:

    ()->{ }

    代碼實現:

    public static void printDir3(File dir) {// lambda的改寫File[] files = dir.listFiles(f ->{ return f.getName().endsWith(".java") || f.isDirectory(); });// 循環打印for (File file : files) {if (file.isFile()) {System.out.println("文件名:" + file.getAbsolutePath());} else {printDir3(file);}} }

    IO

    IO的分類

    根據數據的流向分為:輸入流輸出流

    • 輸入流 :把數據從其他設備上讀取到內存中的流。
    • 輸出流 :把數據從內存 中寫出到其他設備上的流。

    格局數據的類型分為:字節流字符流

    • 字節流 :以字節為單位,讀寫數據的流。
    • 字符流 :以字符為單位,讀寫數據的流。

    流:數據(字符,字節)一個字符=兩個字節
    一個字節=八個二進制(八位)

    ::輸入流輸出流
    字節流字節輸入流
    InputStream
    字節輸出流
    OutputStream
    字符流字符輸入流
    Reader
    字符輸出流
    Writer

    IO字節流

    以二進制數字的形式保存,都一個一個的字節,那么傳輸時一樣如此

    字節輸出流OutputStream

    java.io.OutputStream抽象類是表示字節輸出流的所有類的超類,將指定的字節信息寫出到目的地。它定義了字節輸出流的基本共性功能方法。

    • public void close() :關閉此輸出流并釋放與此流相關聯的任何系統資源。
    • public void flush() :刷新此輸出流并強制任何緩沖的輸出字節被寫出。
    • public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。
    • public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。
    • public abstract void write(int b) :將指定的字節輸出流。

    close方法,當完成流的操作時,必須調用此方法,釋放系統資源。

    FileOutputStream類:文件輸出流

    java.io.FileOutputStream類是文件輸出流,用于將內存數據寫出到硬盤的文件中。

    構造方法

    • public FileOutputStream(File file):創建文件輸出流以寫入由指定的 File對象表示的文件。
    • public FileOutputStream(String name): 創建文件輸出流以指定的名稱寫入文件。

    參數:寫入數據的目的地。
    String name文件路徑
    File file:目的地是一個文件
    構造方法地作用:
    1.創建一個 FileOutputStream對象
    2.會根據構造方法中傳遞的文件/文件路徑,創建一個空的文件
    3.會把 FileOutputStream對象指向創建好的問文件

    字節流寫入數據到文件

    寫出字節
    寫入數據的原理:(內存–>硬盤)
    java程序—>JVM(Java虛擬機)—>Os(操作系統)—>OS調用寫數據的方法—>把數據寫入到文件中

    字節輸出流的使用步驟:

  • 創建一個 FileOutputStream對象,構造方法中傳遞寫入的數據的目的地
  • 調用 FileOutputStream對象中的方法write,把數據寫入到文件中
  • 釋放資源(流使用會占用一定的內存,使用完畢要把內存清空,提供程序的效率)
  • 需要拋出異常

    public class FOSWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileOutputStream fos = new FileOutputStream("fos.txt"); // 寫出數據fos.write(97); // 寫出第1個字節fos.write(98); // 寫出第2個字節fos.write(99); // 寫出第3個字節// 關閉資源fos.close();} } 輸出結果: abc

    寫數據的時候,會把10進制的整數轉換為二進制整數97
    當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有這個文件,會創建該文件。如果有這個文件,會清空這個文件的數據。

    寫出字節數組:write(byte[] b),
    一次寫多個字節

  • 創建 FileOutputStream對象, 構造方法中綁定要寫入的數據的目的地
  • 調用 FileOutputStream對象中的方法write(byte[] b)(如果第一個字節是正數(0–127 ),那么顯示的時候會查詢ascii表 ,如果第一個字節是負數,那么第一個字節會和第二個字節,兩個字節組成 一個中文顯示,查詢系統默認碼表(GBK)),把數據寫入到文本中.
  • 釋放資源
  • public class FOSWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileOutputStream fos = new FileOutputStream("fos.txt"); // 字符串轉換為字節數組byte[] b = "黑馬程序員".getBytes();// 寫出字節數組數據fos.write(b);// 關閉資源fos.close();} }

    寫出指定長度字節數組:write(byte[] b, int off, int len) ,每次寫出從off索引開始,len個字節。把字節數組的一部寫入到文件中

    .getBytes()把字符串轉換為字節數組
    arrays.toString(字節數組)轉換為十進制數組

    public class FOSWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileOutputStream fos = new FileOutputStream("fos.txt"); // 字符串轉換為字節數組byte[] b = "abcde".getBytes();// 寫出從索引2開始,2個字節。索引2是c,兩個字節,也就是cd。fos.write(b,2,2);// 關閉資源fos.close();} } 輸出結果: cd

    數據追加續寫

    ** 追加寫**:使用兩個參數的構造方法

    • public FileOutputStream(File file, boolean append): 創建文件輸出流以寫入由指定的 File對象表示的文件。
      -創建一個向指定File對象表示的文件中寫入數據的文件輸出流

    • public FileOutputStream(String name, boolean append): 創建文件輸出流以指定的名稱寫入文件

    • 創建一個向具有指定name的文件中寫入數據的輸出文件流

    String 那么,File file:寫入數據的目的地
    boolean append:追加寫開關

    true:創建對象不回覆蓋原文件,繼續在文件的末尾追加寫數據
    false:創建一個新文件,覆蓋原文件

    寫換行:寫換行符號
    windows:\r\n
    linux: /n
    mac:/r

    public class FOSWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileOutputStream fos = new FileOutputStream("fos.txt"); // 定義字節數組byte[] words = {97,98,99,100,101};// 遍歷數組for (int i = 0; i < words.length; i++) {// 寫出一個字節fos.write(words[i]);// 寫出一個換行, 換行符號轉成數組寫出fos.write("\r\n".getBytes());}// 關閉資源fos.close();} }輸出結果: a b c d e

    字節輸入流InputStream

    java.io.InputStream抽象類是表示字節輸入流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸入流的基本共性功能方法。

    所有子類共性的方法:

    • public void close() :關閉此輸入流并釋放與此流相關聯的任何系統資源。

    • public abstract int read(): 從輸入流讀取數據的下一個字節。

    • public int read(byte[] b): 從輸入流中讀取一些字節數,并將它們存儲到字節數組 b中 。

    close方法,當完成流的操作時,必須調用此方法,釋放系統資源。

    FileInputStream類

    作用:把硬盤中的文件數據,讀取到內存中使用
    構造方法

    • FileInputStream(File file): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。

    • FileInputStream(String name): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名 name命名。

    當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有該文件,會拋出FileNotFoundException 。

    參數:讀取文件的數據源
    String name:文件路徑
    File file:文件

    構造方法的作用:
    1.會創建一個FileInputStream對象
    2.會把FileInputStream對象指定給構造方法中讀取的文件

    讀取數據的原理(硬盤–>內存)
    java程序 -->JVM -->OS–>OS讀取數據的方法–>讀取文件
    自己輸入流的使用步驟(重點):

  • 創建FileInputStream對象,構造方法中綁定要讀取的數據源。
  • 使用FileInputStream對象中的方法read,讀取文件
  • 釋放文件
  • 讀取字節數據

  • 讀取字節:read方法,每次可以讀取一個字節的數據,提升為int類型,讀取到文件末尾,返回-1,代碼使用演示:
  • 每次讀取一個字節

    public class FISRead {public static void main(String[] args) throws IOException{// 使用文件名稱創建流對象FileInputStream fis = new FileInputStream("read.txt");// 讀取數據,返回一個字節int read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);// 讀取到末尾,返回-1read = fis.read();System.out.println( read);// 關閉資源fis.close();} } 輸出結果: a b c d e -1

    循環改進讀取方式,代碼使用演示:
    不知道文件有多少字節,使用while循環
    結束條件:讀取到-1的時候

    public class FISRead {public static void main(String[] args) throws IOException{// 使用文件名稱創建流對象FileInputStream fis = new FileInputStream("read.txt");// 定義變量,保存數據int b ;// 循環讀取,必須用變量接收while ((b = fis.read())!=-1) {System.out.println((char)b);}// 關閉資源fis.close();} } 輸出結果: a b c d e

    . 使用字節數組讀取:read(byte[] b),每次讀取b的長度個字節到數組中,返回讀取到的有效字節個數,讀取到末尾時,返回-1 ,:

    public class FISRead {public static void main(String[] args) throws IOException{// 使用文件名稱創建流對象.FileInputStream fis = new FileInputStream("read.txt"); // 文件中為abcde// 定義變量,作為有效個數int len ;// 定義字節數組,作為裝字節數據的容器 byte[] b = new byte[2];// 循環讀取while (( len= fis.read(b))!=-1) {// 每次讀取后,把數組的有效字節部分,變成字符串打印System.out.println(new String(b,0,len));// len 每次讀取的有效字節個數}// 關閉資源fis.close();} }輸出結果: ab cd e

    一次讀取多個字節
    原理:
    1.創建一個流對象,并把它指向要讀取的文件
    2.創建一個byte數組
    3.讀取數據

    • 讀取數組長度大小的數據
    • 返回有效讀取字節個數

    數組起到緩沖作用,存儲讀取到的多個字節 一般定義為1024的整數倍

    字節流練習:圖片復制

    文件復制:一讀一寫
    明確:
    數據源
    數據的目的地:

  • 創建一個字節輸入流對象,在構造方法中綁定要讀取的數據源
  • 創建一個
  • 流對象,構造方法中綁定要寫入的目的地
  • 使用字節輸入流對象中的當打中read讀取文件
  • 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地文件中
  • 釋放資源
  • public class Copy {public static void main(String[] args) throws IOException {// 1.創建流對象// 1.1 指定數據源FileInputStream fis = new FileInputStream("D:\\test.jpg");// 1.2 指定目的地FileOutputStream fos = new FileOutputStream("test_copy.jpg");// 2.讀寫數據// 2.1 定義數組byte[] b = new byte[1024];// 2.2 定義長度int len;// 2.3 循環讀取while ((len = fis.read(b))!=-1) {// 2.4 寫出數據fos.write(b, 0 , len);}// 3.關閉資源fos.close();fis.close();} }

    字符流

    當使用字節流讀取文本文件時,可能會有一個小問題。就是遇到中文字符時,可能不會顯示完整的字符,那是因為一個中文字符可能占用多個字節存儲。所以Java提供一些字符流類,以字符為單位讀寫數據,專門用于處理文本文件。

    GBK:占用兩個字節
    utf-8:占用三個字節

    字符輸入流【Reader】

    java.io.Reader抽象類是表示用于讀取字符流的所有類的超類,可以讀取字符信息到內存中。它定義了字符輸入流的基本共性功能方法。

    共有成員方法

    • public int read(): 從輸入流讀取一個字符。
    • public int read(char[] cbuf): 從輸入流中讀取多個字符,并將它們存儲到字符數組 cbuf中 。
    • public void close() :關閉此流并釋放與此流相關聯的任何系統資源。

    FileReader類 文件字符輸入流

    java.io.FileReaderextend InputStreamReader··extendReader類
    是讀取字符文件的便利類。構造時使用系統默認的字符編碼和默認字節緩沖區。

    作用:把硬盤中的數據以字符的方式讀取到內存中

    構造方法:

    • FileReader(File file): 創建一個新的 FileReader ,給定要讀取的File對象。
    • FileReader(String fileName): 創建一個新的 FileReader ,給定要讀取的文件的名稱。
      參數:讀取的數據源
      String fileName:文件的路徑
      File file:文件
      FileReader構造方法中的作用:
      1.創建一個FileReader的對象
      2.會把FileReader對象指向要讀取的文件
      當你創建一個流對象時,必須傳入一個文件路徑。類似于FileInputStream 。
  • 字符編碼:字節與字符的對應規則。Windows系統的中文編碼默認是GBK編碼表。

    idea中UTF-8

  • 字節緩沖區:一個字節數組,用來臨時存儲字節數據。

  • 字符輸入流的使用步驟?
    1.創建FileReader對象,構造方法中要綁定要讀取的數據源
    2.使用FileReader對象中的方法Read讀取文件
    3.釋放資源

    讀取字符數據

  • 讀取字符:read方法,每次可以讀取一個字符的數據,提升為int類型,讀取到文件末尾,返回-1,循環讀取,代碼使用演示:
  • public class FRRead {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileReader fr = new FileReader("read.txt");// 定義變量,保存數據int b ;// 循環讀取while ((b = fr.read())!=-1) {System.out.println((char)b);}// 關閉資源fr.close();} } 輸出結果: 黑 馬 程 序 員

    使用字符數組讀取:read(char[] cbuf),每次讀取b的長度個字符到數組中,返回讀取到的有效字符個數,讀取到末尾時,返回-1 ,代碼使用演示:

    String類構造方法:
    String(char[] value):把字符數組轉換為字符串
    String(char[] value,int offset ,int count):把字符數組一部分轉換為字符串

    public class FRRead {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileReader fr = new FileReader("read.txt");// 定義變量,保存有效字符個數int len ;// 定義字符數組,作為裝字符數據的容器char[] cbuf = new char[2];// 循環讀取while ((len = fr.read(cbuf))!=-1) {System.out.println(new String(cbuf));}// 關閉資源fr.close();} } 輸出結果: 黑馬 程序 員序

    獲取有效的字符改進,代碼使用演示:

    public class FISRead {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileReader fr = new FileReader("read.txt");// 定義變量,保存有效字符個數int len ;// 定義字符數組,作為裝字符數據的容器char[] cbuf = new char[2];// 循環讀取while ((len = fr.read(cbuf))!=-1) {System.out.println(new String(cbuf,0,len));}// 關閉資源fr.close();} }輸出結果: 黑馬 程序 員

    字符輸出流【Writer】

    java.io.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() 關閉此流,但要先刷新它。

    FileWriter類 文件字符輸出流

    作用: 把內存中的字符數數劇寫入到文件中
    java.io.FileWriterextends OutputStreamWrite extends··Write
    java.io.FileWriter類是寫出字符到文件的便利類。構造時使用系統默認的字符編碼和默認字節緩沖區。

    構造方法:

    • FileWriter(File file): 創建一個新的 FileWriter,給定要讀取的File對象。
    • FileWriter(String fileName): 創建一個新的 FileWriter,給定要讀取的文件的名稱。

    當你創建一個流對象時,必須傳入一個文件路徑,類似于FileOutputStream。

    參數:寫入文件的目的地
    String fileName:文件的路徑
    File file:文件
    構造方法中的作用:

  • 會創建一個FileWriter對象
  • 會根據構造方法中傳遞的文件/文件路徑創建文件
  • 會把FileWriter對象指向創建好的文件
  • 字符輸出流的使用步驟:

  • 創建FileWriter對象。構造方法中綁定要寫入的數據的目的地
  • 使用FileWriter中的方法write,把數據寫入到內存緩沖區中(字符轉換為字節的過程)
  • 使用FileWriter中的方法flush,把內存緩沖區中的數據,刷新到文件中
  • 釋放資源(會先把內存緩沖區中的數據,刷新到文件中)
  • 基本寫出數據

    寫出單個字符:write(int b) 方法,每次可以寫出一個字符數據,代碼使用演示:

    public class FWWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileWriter fw = new FileWriter("fw.txt"); // 寫出數據fw.write(97); // 寫出第1個字符fw.write('b'); // 寫出第2個字符fw.write('C'); // 寫出第3個字符fw.write(30000); // 寫出第4個字符,中文編碼表中30000對應一個漢字。/*【注意】關閉資源時,與FileOutputStream不同。如果不關閉,數據只是保存到緩沖區,并未保存到文件。*/// fw.close();} } 輸出結果: abC田
  • 雖然參數為int類型四個字節,但是只會保留一個字符的信息寫出。
  • 未調用close方法,數據只是保存到了緩沖區,并未寫出到文件中。
  • 關閉和刷新

    因為內置緩沖區的原因,如果不關閉輸出流,無法寫出字符到文件中。但是關閉的流對象,是無法繼續寫出數據的。如果我們既想寫出數據,又想繼續使用流,就需要flush 方法了。

    • flush :刷新緩沖區,流對象可以繼續使用。
    • close:先刷新緩沖區,然后通知系統釋放資源。流對象不可以再被使用了。

    寫出其他數據

  • 寫出字符數組 :write(char[] cbuf) 和 write(char[] cbuf, int off, int len) ,每次可以寫出字符數組中的數據,用法類似FileOutputStream,代碼使用演示:
  • public class FWWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileWriter fw = new FileWriter("fw.txt"); // 字符串轉換為字節數組char[] chars = "黑馬程序員".toCharArray();// 寫出字符數組fw.write(chars); // 黑馬程序員// 寫出從索引2開始,2個字節。索引2是'程',兩個字節,也就是'程序'。fw.write(b,2,2); // 程序// 關閉資源fos.close();} }
  • 寫出字符串:write(String str) 和 write(String str, int off, int len) ,每次可以寫出字符串中的數據,更為方便,代碼使用演示:
  • public class FWWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象FileWriter fw = new FileWriter("fw.txt"); // 字符串String msg = "黑馬程序員";// 寫出字符數組fw.write(msg); //黑馬程序員// 寫出從索引2開始,2個字節。索引2是'程',兩個字節,也就是'程序'。fw.write(msg,2,2); // 程序// 關閉資源fos.close();} }
  • 續寫和換行:操作類似于FileOutputStream。
    使用兩個參數的構造方法:
    FileWriter(String fileName,Boolean append)
    FileWriter(File file,Boolean append)
  • Boolean append:
    true:可以續寫,不回創建新的文件覆蓋源文件
    false:創建新的文件覆蓋源文件

    public class FWWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創建流對象,可以續寫數據FileWriter fw = new FileWriter("fw.txt"true); // 寫出字符串fw.write("黑馬");// 寫出換行fw.write("\r\n");// 寫出字符串fw.write("程序員");// 關閉資源fw.close();} } 輸出結果: 黑馬 程序員

    流中的異常處理

    jdk1.7之前使用try...catch...finally處理流中的異常

    public class HandleException1 {public static void main(String[] args) {// 聲明變量,提高變量作用域,聲明時可以沒有值,使用時必須有值FileWriter fw = null;try {//可能會出現異常的代碼創建流對象fw = new FileWriter("fw.txt");// 寫出數據fw.write("黑馬程序員"); //黑馬程序員} catch (IOException e) {//異常的處理邏輯e.printStackTrace();} finally {try { //若創建對象失敗,fw默認值時null,null不能調用方法,會拋出nullponitException,需要增加一個判斷不是null,則釋放資源if (fw != null) {fw.close();}} catch (IOException e) {e.printStackTrace();}}} }

    JDK7的新特性:
    在try之后增加一個();
    在括號中可以定義流對象,那么這個流對象的作用域就在try中有效,try中代碼執行完畢,會自動把流對象釋放掉,不用寫finally,
    格式如下:

    try (創建流對象語句,如果多個,使用';'隔開) {// 讀寫數據 } catch (IOException e) {e.printStackTrace(); }

    代碼使用演示:

    public class HandleException2 {public static void main(String[] args) {// 創建流對象try ( FileWriter fw = new FileWriter("fw.txt"); ) {// 寫出數據fw.write("黑馬程序員"); //黑馬程序員} catch (IOException e) {e.printStackTrace();}} }

    JDK9的改進(擴展知識點了解內容)

    try的前邊可以定義流對象
    在try后邊()中可以直接引入流對象的名稱(變量名)
    在try代碼執行完畢之后流對象也可以釋放掉,不用寫finally

    JDK9中try-with-resource 的改進,對于引入對象的方式,支持的更加簡潔。被引入的對象,同樣可以自動關閉,無需手動close,我們來了解一下格式。
    A a =new A();
    B b=new B();
    try(a,b){
    可能會產出異常的代碼,
    } catch(異常類變量 變量名){
    異常的處理邏輯
    }

    public class TryDemo {public static void main(String[] args) throws IOException {// 創建流對象** final ** FileReader fr = new FileReader("in.txt");FileWriter fw = new FileWriter("out.txt");// 引入到try中try (fr; fw) {// 定義變量int b;// 讀取數據while ((b = fr.read())!=-1) {// 寫出數據fw.write(b);}} catch (IOException e) {e.printStackTrace();}} }

    屬性集

    概述

    java.util.Properties 繼承于Hashtable ,來表示一個持久的屬性集。它使用鍵值結構存儲數據,每個鍵及其對應值都是一個字符串。該類也被許多Java類使用,比如獲取系統屬性時,System.getProperties 方法就是返回一個Properties對象。

    java.util.Properties extends hashtable<K,v>implements Map<K,v>

    Properties類

    表示了一個持久的屬性集Properties可保存在流中或從流中加載。

    Properties集合是唯一一個和IO流相結合的集合

    可以使用Properties集合中的臨時數據,持久化寫入到硬盤中存儲、

    可以使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用

    Properties屬性列表中每個鍵及其對對應的值都是一個字符串

    Properties是一個雙列集合,key和value默認都是字符串

    構造方法

    • public Properties() :創建一個空的屬性列表。

    基本的存儲方法

    使用Properties結合存儲數據,遍歷取出Properties集合中的數據
    是一個雙列集合,Key和value都是字符串

    • public Object setProperty(String key, String value) : 保存一對屬性。 調用hashtable的方法put
    • public String getProperty(String key) :使用此屬性列表中指定的鍵搜索屬性值。通過key找到value值,此方法相當于map集合中的get(key)方法
    • public Set<String> stringPropertyNames() :所有鍵的名稱的集合。返回此屬性列表中的鍵集,其中該鍵及其對應值是字符串,此方法相當于Map集合中的KeySet方法
    public class ProDemo {public static void main(String[] args) throws FileNotFoundException {// 創建屬性集對象Properties properties = new Properties();// 添加鍵值對元素properties.setProperty("filename", "a.txt");properties.setProperty("length", "209385038");properties.setProperty("location", "D:\\a.txt");// 打印屬性集對象System.out.println(properties);// 通過鍵,獲取屬性值System.out.println(properties.getProperty("filename"));System.out.println(properties.getProperty("length"));System.out.println(properties.getProperty("location"));// 遍歷屬性集,獲取所有鍵的集合Set<String> strings = properties.stringPropertyNames();// 打印鍵值對for (String key : strings ) {System.out.println(key+" -- "+properties.getProperty(key));}} }輸出結果: {filename=a.txt, length=209385038, location=D:\a.txt} a.txt 209385038 D:\a.txt filename -- a.txt length -- 209385038 location -- D:\a.txt

    與流相關的方法

    可以使用properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲

    void store (OutputStream out,String comments)
    void store(Write write,String comments)
    參數:
    OutputStream out:不可以寫入中文
    Write write:字符輸出流,可以寫入中文
    String comments:注釋,用來解釋說明保存的文件是做什么用的,不能使用中文,會產生亂碼默認unicide編碼,一般使用“空字符串”

    使用步驟:

  • 創建Properties 集合對象,添加數據
  • 創建字節輸出流/字符輸出流對象,構造方法中綁定要輸出的目的地
  • 使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲
  • 釋放資源
  • Properties pro = new Properties();創建Properties集合 pro.setProperty(“11”,“11 ”); FileWrite fw=new FileWrite("Filename"); pro.store(fw,"savedate"); fw.close();

    可以使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用

    • public void load(InputStream inStream): 從字節輸入流中讀取鍵值對。
    • public void load(Reader reader):

    參數:
    (InputStream inStream):字節輸入流,不能讀取含有中文的鍵值對,
    Reader reader:字符輸入流,可以讀取含有中文的鍵值對

    通過流對象,可以關聯到某文件上,這樣就能夠加載文本中的數據了。文本數據格式:

    使用步驟:

  • 創建Properties集合對象
  • 使用Properties集合對象中的方法load讀取保存鍵值對文件
  • 遍歷Properties集合
  • 注意:

  • 存儲鍵值對的文件中,鍵與值默認的連接符號使用=, 空格(其他符號)
  • 存儲鍵值對的文件中,可使用#進行注釋,被注釋的鍵值對不會再被讀取
  • 鍵與值默認都是字符串,不用再加引號
  • filename=a.txt length=209385038 location=D:\a.txt

    加載代碼演示:
    一般使用字符流

    public class ProDemo2 {public static void main(String[] args) throws FileNotFoundException {// 創建屬性集對象Properties pro = new Properties();// 加載文本中信息到屬性集pro.load(new FileInputStream("read.txt"));// 遍歷集合并打印Set<String> strings = pro.stringPropertyNames();for (String key : strings ) {System.out.println(key+" -- "+pro.getProperty(key));}} } 輸出結果: filename -- a.txt length -- 209385038 location -- D:\a.txt

    小貼士:文本中的數據,必須是鍵值對形式,可以使用空格、等號、冒號等符號分隔。

    緩沖流,也叫高效流,是對4個基本的FileXxx 流的增強,所以也是4個流,按照數據類型分類:

    緩沖流

    緩沖流的基本原理,是在創建流對象時,會創建一個內置的默認大小的緩沖區數組,通過緩沖區讀寫,減少系統IO次數,從而提高讀寫的效率。

    字節緩沖流

    BufferedInputStream,字節緩沖輸入流

    所有子類共性的方法:

    • public void close() :關閉此輸入流并釋放與此流相關聯的任何系統資源。

    • public abstract int read(): 從輸入流讀取數據的下一個字節。

    • public int read(byte[] b): 從輸入流中讀取一些字節數,并將它們存儲到字節數組 b中 。

    close方法,當完成流的操作時,必須調用此方法,釋放系統資源。

    BufferedOutputStream 字節緩沖輸出流

    共性方法:

    • public void close() :關閉此輸出流并釋放與此流相關聯的任何系統資源。
    • public void flush() :刷新此輸出流并強制任何緩沖的輸出字節被寫出。
    • public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。
    • public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。
    • public abstract void write(int b) :將指定的字節輸出流。

    close方法,當完成流的操作時,必須調用此方法,釋放系統資源。


    字節緩沖輸入流

    構造方法

    • public BufferedInputStream(InputStream in) :創建一個 新的緩沖輸入流。 ,保存其參數,即輸入流in,以便將來使用
    • public BufferedInputStream(InputStream in,int size ) :創建一個 具有指定緩沖區大小的緩沖輸入流,并保存其參數

    參數:
    InputStream in字節輸入流:我們可以傳遞FileInputStream,增加一個緩沖區,提高FileInputStream的讀取效率
    int size:指定緩沖流內部緩沖區大小,不指定默認

    使用步驟
    1.創建FileInputStream對象,構造方法中綁定要讀取的數據源
    2.創建BufferedInputStream對象,構造方法中傳遞FileInputStream對象,提高FileInputStream對象效率
    3.使用BufferedInputStream對象中的方法read ,讀取文件
    4.釋放資源(會調用Flue方法刷新數據)


    字節緩沖輸出流
    • public BufferedOutputStream(OutputStream out): 創建一個新的緩沖輸出流。以將數據寫入指定的底層輸出流

    • public BufferedOutputStream(OutputStream out,int size): 創建一個新的緩沖輸出流。以將數據寫入指定的底層輸出流

    參數
    OutputStream out:字節輸出流
    我們可以傳遞FileOutputStream,緩沖流會給FileOutoutStream增加一個緩沖區,提高FileOutputStream 的寫入效率

    使用步驟
    1.創建FileOutputStream對象,構造方法中綁定要輸出目的地
    2.創建BufferedOutputStream對象,構造方法中傳遞FileOutputStream對象 對象,提高FileOutputStream對象效率
    3.使用BufferedOutputStream對象中的方法write,把數據寫入到內部緩沖區,

    4.使用BufferedOutputStream對象中的方法flush把內部緩沖區中的數據,刷新到文件中
    5.釋放資源(會調用Flue方法刷新數據)

    構造舉例,代碼如下:

    // 創建字節緩沖輸入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt")); // 創建字節緩沖輸出流 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

    關閉緩沖流,會自動關閉基本流

    效率測試

  • 基本流,代碼如下:
  • public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創建流對象try (FileInputStream fis = new FileInputStream("jdk9.exe");FileOutputStream fos = new FileOutputStream("copy.exe")){// 讀寫數據int b;while ((b = fis.read()) != -1) {fos.write(b);}} catch (IOException e) {e.printStackTrace();}// 記錄結束時間long end = System.currentTimeMillis();System.out.println("普通流復制時間:"+(end - start)+" 毫秒");} }十幾分鐘過去了...
  • 緩沖流,代碼如下:
  • public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創建流對象try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk9.exe"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));){// 讀寫數據int b;while ((b = bis.read()) != -1) {bos.write(b);}} catch (IOException e) {e.printStackTrace();}// 記錄結束時間long end = System.currentTimeMillis();System.out.println("緩沖流復制時間:"+(end - start)+" 毫秒");} }緩沖流復制時間:8016 毫秒

    如何更快呢?

    使用數組的方式,代碼如下:

    public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創建流對象try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk9.exe"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));){// 讀寫數據int len;byte[] bytes = new byte[8*1024];while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0 , len);}} catch (IOException e) {e.printStackTrace();}// 記錄結束時間long end = System.currentTimeMillis();System.out.println("緩沖流使用數組復制時間:"+(end - start)+" 毫秒");} } 緩沖流使用數組復制時間:666 毫秒

    字符緩沖流

    共性方法

    • 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() 關閉此流,但要先刷新它。

    BufferedWriter字符緩沖輸出流

    構造方法
    BufferedWriter(writer out):創建一個使用默認大小輸出緩沖區的緩沖輸出流

    BufferedWriter(writer out,int sz):創建一個使用給定大小輸出緩沖區的新緩沖字符輸出流

    參數:
    writer out:字符輸出流
    我們可以傳遞一個FileWriter,緩沖流會給FileWriter增加一個緩沖區,提高FileWrite的寫入效率
    int sz:指定緩沖區的大小,不寫默認大小

    特有成員方法:
    Void newLine():寫入一個分隔符,會根據不同的操作系統,獲取不同的行分隔符
    換行符號:
    windows:\r\n
    linux:/n
    mac:/r

    使用步驟:
    1.創建字符緩沖輸出流對象,構造方法中傳遞字符輸出流
    2.調用字符緩沖流中的方法,write,把數據寫入到內存緩沖區中
    3.調用字符緩沖流中的方法flush,把內存緩沖區中的數據,刷新到文件中
    4.釋放資源

    BufferedReader,extends Reader 字符緩沖輸入流

    • 共有成員方法
    • public int read(): 從輸入流讀取一個字符。
    • public int read(char[] cbuf): 從輸入流中讀取多個字符,并將它們存儲到字符數組 cbuf中 。
    • public void close() :關閉此流并釋放與此流相關聯的任何系統資源。

    構造方法
    BufferedReader(Reader in):創建一個使用默認大小的輸出緩沖的緩沖字符輸入流

    BufferedReader(Reader in,int sz):創建一個使用指定大小的緩沖區的緩沖字符輸入流
    參數
    Reader in:字符輸入流我們可以傳遞FileReader,緩沖流會給FileReader增加一個緩沖區,提高FileReader的讀取效率

    int sz:
    特有成員方法
    String readLine():讀取一個文本行 。讀一行數據,行的終止符號:通過列字符之一即可認為某行已終止,換行\n 回車\r,回車后跟著換行(\r\n)
    返回值:包含該行內容字符串,不包含任何行終止符,如果已到達流末尾,則返回null

    使用步驟

  • 創建字符緩沖輸入流對象,構造方法中傳遞字符輸入流
  • 使用字符緩沖輸入流對象中的方法read/readline讀取文本
  • 釋放資源
    readLine方法演示,代碼如下:
  • public class BufferedReaderDemo {public static void main(String[] args) throws IOException {// 創建流對象BufferedReader br = new BufferedReader(new FileReader("in.txt"));// 定義字符串,保存讀取的一行文字String line = null;// 循環讀取,讀取到最后返回nullwhile ((line = br.readLine())!=null) {System.out.print(line);System.out.println("------");}// 釋放資源br.close();} }

    1.4 練習:文本排序

    練習:
    對文本的內容進行排序

    3.侍中、侍郎郭攸之、費祎、董允等,此皆良實,志慮忠純,是以先帝簡拔以遺陛下。愚以為宮中之事,事無大小,悉以咨之,然后施行,必得裨補闕漏,有所廣益。 8.愿陛下托臣以討賊興復之效,不效,則治臣之罪,以告先帝之靈。若無興德之言,則責攸之、祎、允等之慢,以彰其咎;陛下亦宜自謀,以咨諏善道,察納雅言,深追先帝遺詔,臣不勝受恩感激。 4.將軍向寵,性行淑均,曉暢軍事,試用之于昔日,先帝稱之曰能,是以眾議舉寵為督。愚以為營中之事,悉以咨之,必能使行陣和睦,優劣得所。 2.宮中府中,俱為一體,陟罰臧否,不宜異同。若有作奸犯科及為忠善者,宜付有司論其刑賞,以昭陛下平明之理,不宜偏私,使內外異法也。 1.先帝創業未半而中道崩殂,今天下三分,益州疲弊,此誠危急存亡之秋也。然侍衛之臣不懈于內,忠志之士忘身于外者,蓋追先帝之殊遇,欲報之于陛下也。誠宜開張圣聽,以光先帝遺德,恢弘志士之氣,不宜妄自菲薄,引喻失義,以塞忠諫之路也。 9.今當遠離,臨表涕零,不知所言。 6.臣本布衣,躬耕于南陽,茍全性命于亂世,不求聞達于諸侯。先帝不以臣卑鄙,猥自枉屈,三顧臣于草廬之中,咨臣以當世之事,由是感激,遂許先帝以驅馳。后值傾覆,受任于敗軍之際,奉命于危難之間,爾來二十有一年矣。 7.先帝知臣謹慎,故臨崩寄臣以大事也。受命以來,夙夜憂嘆,恐付托不效,以傷先帝之明,故五月渡瀘,深入不毛。今南方已定,兵甲已足,當獎率三軍,北定中原,庶竭駑鈍,攘除奸兇,興復漢室,還于舊都。此臣所以報先帝而忠陛下之職分也。至于斟酌損益,進盡忠言,則攸之、祎、允之任也。 5.親賢臣,遠小人,此先漢所以興隆也;親小人,遠賢臣,此后漢所以傾頹也。先帝在時,每與臣論此事,未嘗不嘆息痛恨于桓、靈也。侍中、尚書、長史、參軍,此悉貞良死節之臣,愿陛下親之信之,則漢室之隆,可計日而待也。

    案例分析

    1.創建一個HashMap集合對象,可以存儲每行文本的序號,value存儲每行的文本
    2.創建字符緩沖輸入流對象,構造方法綁定字符輸入流
    3.創建字符緩沖輸出流對象,構造方法中綁定字符輸出流
    4.使用字符緩沖輸入流的方法readLine,逐行讀取文本
    5.對讀取到的文本 進行切割,獲取行中的序號和文本內容
    6.把切割好的序號和文本的內容存儲到Hashmap集合中(key序號是有序的,會自動排序)
    7.遍歷HashMap集合,獲取每一個鍵值對
    8.把每一個鍵值對拼接為一個文本行
    9.把拼接好的文本,使用字符緩沖輸出流中的方法write,寫入到文件中
    10.釋放資源

    案例實現

    public class BufferedTest {public static void main(String[] args) throws IOException {//1. 創建map集合,保存文本數據,鍵為序號,值為文字HashMap<String, String> lineMap = new HashMap<>();// 2.創建字符緩沖輸入流對象,構造方法中綁定字符輸入流BufferedReader br = new BufferedReader(new FileReader("in.txt"));//3.創建一個字符緩沖輸出流對象,構造方法中綁定字符串輸出流BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt")); //4.使用字符緩沖輸出流中的方法readLine逐行讀取文本// 讀取數據String line = null;while ((line = br.readLine())!=null) {// 解析文本String[] split = line.split("\\.");// 保存到集合lineMap.put(split[0],split[1]);}// 釋放資源br.close();// 遍歷map集合for (int i = 1; i <= lineMap.size(); i++) {String key = String.valueOf(i);// 獲取map中文本String value = lineMap.get(key);// 寫出拼接文本bw.write(key+"."+value);// 寫出換行bw.newLine();}// 釋放資源bw.close();} }

    轉換流

    字符編碼和字符集

    按照某種規則,將字符存儲到計算機中,稱為編碼 。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱為解碼

    字符編碼:就是一套自然語音字符與二進制數之間的對應規則

    字符集:也叫編碼表,是一個系統支持所有字符的集合

    Idea默認編碼utf-8

    FileReader可以讀取IO默認編碼格式UTF-8的文件
    FileReader讀取系統默認編碼GBK中文 會產生亂碼

    InputStreamReader類

    轉換流java.io.InputStreamReader,是Reader的子類,是從字節流到字符流的橋梁。
    它讀取字節,并使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。

    構造方法

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

    參數:
    InputSrteam in:字節輸入流,用來讀取文件中保存的字節
    String charsetName:指定的編碼表名稱,不區分大小寫,可以實Utf-8,Gbk。。。。不指定默認使用UTF-8

    使用步驟:

  • 創建InputStreamReader對象,構造方法重視傳遞字節輸出流和指定的編碼表名稱。
  • 使用InputStreamReader對象中的方法read讀取文件
  • 釋放資源
  • 注意事項:
    構造方法中指定的編碼表民晨光要和文件的編碼相同,否則會發生亂碼

    OutputStreamWriter類

    轉換流java.io.OutputStreamWriter ,是Writer的子類,是從字符流到字節流的橋梁。使用指定的字符集將字符編碼為字節。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。

    構造方法

    • OutputStreamWriter(OutputStream in): 創建一個使用默認字符集的字符流。
    • OutputStreamWriter(OutputStream in, String charsetName): 創建一個指定字符集的字符流。

    參數
    OutputStream out:字節輸出流,用來寫轉換之后的字節到文件中
    String charsetName:指定的編碼表名稱,不區分大小寫,可以是Utf-8,GBK…,不指定默認使用Utf-8

    使用步驟

  • 創建OutputStreamWrite對象,構造方法中傳遞字節輸出流和指定編碼表名稱
  • 使用OutputStreamWrite,把字符轉換為字節存儲在緩沖區中(編碼)
  • 使用OutputStreamWrite對象中的方法flush,把內存緩沖區的字節刷新到文件中(使用字節流寫字節的過程)
  • 釋放資源
  • 指定編碼寫出

    public class OutputDemo {public static void main(String[] args) throws IOException {// 定義文件路徑String FileName = "E:\\out.txt";// 創建流對象,默認UTF8編碼OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));// 寫出數據osw.write("你好"); // 保存為6個字節osw.close();// 定義文件路徑String FileName2 = "E:\\out2.txt";// 創建流對象,指定GBK編碼OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");// 寫出數據osw2.write("你好");// 保存為4個字節osw2.close();} }

    練習:轉換文件編碼

    將GBK編碼的文本文件,轉換為UTF-8編碼的文本文件。

    案例分析

    1.創建InputStreanReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱GBK
    2.創建OutputStreamWrite對象,構造方法中傳遞字節輸出流和指定的編碼表utf-8
    3.使用InputSteamReader對象中的方法read讀取文件
    4.使用OutputStreamWrite方法write,把讀取的數據寫入到文件中
    5.釋放資源

    案例實現

    public class TransDemo {public static void main(String[] args) { // 1.定義文件路徑String srcFile = "file_gbk.txt";String destFile = "file_utf8.txt";// 2.創建流對象// 2.1 轉換輸入流,指定GBK編碼InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");// 2.2 轉換輸出流,默認utf8編碼OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));// 3.讀寫數據// 3.1 定義數組char[] cbuf = new char[1024];// 3.2 定義長度int len;// 3.3 循環讀取while ((len = isr.read(cbuf))!=-1) {// 循環寫出osw.write(cbuf,0,len);}// 4.釋放資源osw.close();isr.close();} }

    序列化

    概述

    Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據、對象的類型和對象中存儲的屬性等信息。字節序列寫出到文件之后,相當于文件中持久保存了一個對象的信息。

    反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化。對象的數據、對象的類型和對象中存儲的數據信息,都可以用來在內存中創建對象。

    把對象以流的方式,寫入到文件中保存,叫寫對象,也可以叫對象的序列化
    對象中包含的不僅僅是字符使用字節流
    ObjectOutputStream:對象的序列化writeObject(p)

    把文件中保存的對象,以流的方式讀取出來,叫做讀對象,也叫對象的反序列化
    讀取的文件保存的都是字節使用字節流
    ObjectInputStream:對象的反序列化流
    readObject()

    ObjectOutputStream類

    作用:把對象以流的方式寫入到文件中保存
    java.io.ObjectOutputStreamextends OutputStream 類,將Java對象的原始數據類型寫出到文件,實現對象的持久存儲。

    構造方法

    • public ObjectOutputStream(OutputStream out): 創建一個指定OutputStream的ObjectOutputStream。
      參數:

    OutputStream out:字節輸出流

    構造舉例,代碼如下:

    特有的成員方法:

    • public final void writeObject (Object obj) : 將指定的對象寫出。

    使用步驟,需要序列化對象實現類
    1.創建ObjectOutputStream對象,構造方法中傳遞字節輸出流
    2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中
    3.釋放資源

    序列化操作

    1.一個對象要想序列化,必須滿足兩個條件:

    • 該類必須 實現java.io.Serializable 接口來啟用序列化功能,Serializable 是一個標記接口,不實現此接口的類將不會使任何狀態序列化或反序列化,會拋出NotSerializableException 。實現Serializable接口,會給類添加一個標記,當序列化和反序列化的時候,就會檢測類上是否有這個標記

    • 該類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須注明是瞬態的,使用transient 關鍵字修飾。

    • static關鍵字:靜態關鍵字
      靜態優先于非靜態加載到內存中(靜態優先于對象進入到內存中)被static修飾的成員變量不能被序列化

    • transient 瞬態關鍵字: 被其修飾,不能被序列化
    public class Employee implements java.io.Serializable {public String name;public String address;public transient int age; // transient瞬態修飾成員,不會被序列化public void addressCheck() {System.out.println("Address check : " + name + " -- " + address);} }

    2.寫出對象方法

    • public final void writeObject (Object obj) : 將指定的對象寫出。
    public class SerializeDemo{public static void main(String [] args) {Employee e = new Employee();e.name = "zhangsan";e.address = "beiqinglu";e.age = 20; try {// 創建序列化流對象ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));// 寫出對象out.writeObject(e);// 釋放資源out.close();fileOut.close();System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年齡沒有被序列化。} catch(IOException i) {i.printStackTrace();}} } 輸出結果: Serialized data is saved

    ObjectInputStream類

    ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復為對象。
    作用:把文件中保存的對象,以流的方式讀取出來使用

    構造方法

    • public ObjectInputStream(InputStream in): 創建一個指定InputStream的ObjectInputStream。
      參數InputStream in:字節輸入流

    特有成員方法:

    • public final Object readObject () : 從ObjectInputStream讀取一個對象。

    使用步驟:
    1.創建一個ObjectInputStream對象,構造方法中傳遞字節輸入流
    2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件
    3.釋放資源
    4.使用讀取出來的對象

    反序列化操作1

    如果能找到一個對象的class文件,我們可以進行反序列化操作,調用ObjectInputStream讀取對象的方法:

    • public final Object readObject () : 讀取一個對象。

    readObject方法聲明拋出了ClassNotFoundException(class文件找不到異常)當不存在對象的class文件時拋出異常
    反序列化前提:

  • 類必須實現Serializable
  • 必須存在類對應的class文件
  • public class DeserializeDemo {public static void main(String [] args) {Employee e = null;try { // 創建反序列化流FileInputStream fileIn = new FileInputStream("employee.txt");ObjectInputStream in = new ObjectInputStream(fileIn);// 讀取一個對象e = (Employee) in.readObject();// 釋放資源in.close();fileIn.close();}catch(IOException i) {// 捕獲其他異常i.printStackTrace();return;}catch(ClassNotFoundException c) {// 捕獲類找不到異常System.out.println("Employee class not found");c.printStackTrace();return;}// 無異常,直接打印輸出System.out.println("Name: " + e.name); // zhangsanSystem.out.println("Address: " + e.address); // beiqingluSystem.out.println("age: " + e.age); // 0} }

    對于JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個 ClassNotFoundException 異常。

    反序列化操作2

    **另外,當JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之后發生了修改,那么反序列化操作也會失敗,拋出一個InvalidClassException異常。**發生這個異常的原因如下:

    • 該類的序列版本號與從流中讀取的類描述符的版本號不匹配
    • 該類包含未知數據類型
    • 該類沒有可訪問的無參數構造方法

    Serializable 接口給需要序列化的類,提供了一個序列版本號。serialVersionUID 該版本號的目的在于驗證序列化的對象和對應類是否版本匹配。

    問題:
    每次修改類的定義,都會給class文件生成一個新得序列號
    解決方法:
    無論是否對類的定義進行修改,都不生成新的序列號
    可以手動給類添加一個序列號
    格式在Serializable 接口規定:
    可序列化類可以通過聲明為serialVersionUID的字段(該字段必須是static)最終final的long星字段,顯示聲明其自己的serialVersionUID

    static final long serialVersionUID=42L

    public class Employee implements java.io.Serializable {// 加入序列版本號private static final long serialVersionUID = 1L;public String name;public String address;// 添加新的屬性 ,重新編譯, 可以反序列化,該屬性賦為默認值.public int eid; public void addressCheck() {System.out.println("Address check : " + name + " -- " + address);} }

    練習:序列化集合

  • 將存有多個自定義對象的集合序列化操作,保存到list.txt文件中。
  • 反序列化list.txt ,并遍歷集合,打印對象信息。
  • 練習:
    當我們想在文件中保存多個對象的時候
    可以把多個對象存儲到一個集合中
    對象進行序列化和反序列化

    分析:

  • 定義一個存儲Person對象的Array List集合

  • 往ArrayList集合中存儲Person對象

  • 創建一個序列化流ObjectOutputStream

  • 使用ObjectOutputStream對象中的方法writeObject,對集合進行序列化

  • 創建一個反序列化Object InputStream對象

  • 使用ObjectInputStream對象中的方法readObject讀取文件中保存的集合

  • 把Object類型的集合轉換為ArraysList類型

  • 遍歷ArrayList集合

  • 釋放資源

  • 案例分析

  • 把若干學生對象 ,保存到集合中。
  • 把集合序列化。
  • 反序列化讀取時,只需要讀取一次,轉換為集合類型。
  • 遍歷集合,可以打印所有的學生信息
  • 案例實現

    public class SerTest {public static void main(String[] args) throws Exception {// 創建 學生對象Student student = new Student("老王", "laow");Student student2 = new Student("老張", "laoz");Student student3 = new Student("老李", "laol");ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(student);arrayList.add(student2);arrayList.add(student3);// 序列化操作// serializ(arrayList);// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));// 讀取對象,強轉為ArrayList類型ArrayList<Student> list = (ArrayList<Student>)ois.readObject();for (int i = 0; i < list.size(); i++ ){Student s = list.get(i);System.out.println(s.getName()+"--"+ s.getPwd());}}private static void serializ(ArrayList<Student> arrayList) throws Exception {// 創建 序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));// 寫出對象oos.writeObject(arrayList);// 釋放資源oos.close();} }

    打印流

    概述

    平時我們在控制臺打印輸出,是調用print方法和println方法完成的,這兩個方法都來自于java.io.PrintStream類,該類能夠方便地打印各種數據類型的值,是一種便捷的輸出方式。

    PrintStream類extends OutputStream

    為其他輸出流添加了功能,是他們能夠方便的打印各種數據值表示形式

    特點:

  • 只負責數據的輸出,不負責數據的讀取
  • 與其他輸出流不同,其永遠不回拋出IOexception
  • 特有方法:print,println可以輸出任意類型的值
  • 構造方法

    • public PrintStream(String fileName): 使用指定的文件名創建一個新的打印流。輸出目的地是一個文件路徑

    • public PrintStream(File file): 使用指定的文件創建一個新的打印流。輸出目的地是一個文件

    • public PrintStream(Output Stream): 使用指定的輸出流創建一個新的打印流。輸出目的地是一個字節輸出流

    構造舉例,代碼如下:

    PrintStream ps = new PrintStream("ps.txt")

    繼承自父類的成員方法

    • public void close() :關閉此輸出流并釋放與此流相關聯的任何系統資源。
    • public void flush() :刷新此輸出流并強制任何緩沖的輸出字節被寫出。
    • public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。
    • public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。
    • public abstract void write(int b) :將指定的字節輸出流。

    注意事項
    如果使用繼承自父類的write方法寫數據,那么查看數據的時候會查詢編碼表
    如果使用自己特有的print/println方法寫數據,寫的數據會原樣輸出

    使用步驟

  • 創建打印流PrintStream對象,構造方法中綁定要輸出的目的地(會拋出文件找不到異常,不回拋出IO異常)
  • 使用父類方法或自己特有方法
  • 釋放資源
  • 改變打印流向

    System.out就是PrintStream類型的,只不過它的流向是系統規定的,打印在控制臺上。

    可以改變輸出語句的目的地(打印流的流向)
    輸出語句,默認在控制臺輸出
    使用System.setOut方法改變輸出語句的目的地改為參數傳遞的打印流的目的地
    static void setOut(PrintStream out )
    重新分配“標準”輸出流

    public class PrintDemo {public static void main(String[] args) throws IOException {// 調用系統的打印流,控制臺直接輸出97System.out.println(97);// 創建打印流,指定文件的名稱PrintStream ps = new PrintStream("ps.txt");// 設置系統的打印流流向,輸出到ps.txtSystem.setOut(ps);// 調用系統的打印流,ps.txt中輸出97System.out.println(97); ps.close();} }

    總結

    以上是生活随笔為你收集整理的Java笔记整理六(File类,递归,字节流IO,字符流IO,流中的异常处理,属性集Properties,缓冲流,转换流,序列化,打印流)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。