1 File

1.1 File類的概述和構(gòu)造方法

  1. File: 它是文件和目錄路徑名的抽象表示
    • 文件和目錄是可以通過File封裝成對象的
    • 對于File而言,其封裝的并不是一個真正存在的文件,僅僅是一個路徑名而已。它可以是存在的,也可以是不存在的。將來是要通過具體的操作把這個路徑的內(nèi)容轉(zhuǎn)換為具體存在的
方法名說明
File(String pathname)通過將給定的路徑名字符串轉(zhuǎn)換為抽象路徑名來創(chuàng)建新的File實例
File(String parent, String child)從父路徑名字符串和子路徑名字符串創(chuàng)建新的File實例
File(File parent, String child)從父抽象路徑名和子路徑名字符串創(chuàng)建新的File實例

1.2 File類的創(chuàng)建功能

方法名說明
public boolean createNewFile()當具有該名稱的文件不存在時,創(chuàng)建一個由該抽象路徑名命名的新空文件
public boolean mkdir()創(chuàng)建由此抽象路徑名命名的目錄
public boolean mkdirs()創(chuàng)建由此抽象路徑名命名的目錄,包括任何必需但不存在的父目錄

1.3 File類的刪除功能

方法名說明
public boolean delete()刪除由此抽象路徑名表示的文件或目錄
  1. 絕對路徑和相對路徑的區(qū)別

    • 絕對路徑: ==完整的路徑名==,不需要任何其他信息就可以定位它所表示的文件。
    • 相對路徑: 必須使用取自其他路徑名的信息進行解釋。
  2. 刪除目錄時的注意事項
    • 如果一個目錄中有內(nèi)容(目錄,文件),不能直接刪除。應(yīng)該先刪除目錄中的內(nèi)容,最后才能刪除目錄

1.4 File類判斷和獲取功能

方法名說明
public boolean isDirectory()測試此抽象路徑名表示的File是否為目錄
public boolean isFile()測試此抽象路徑名表示的File是否為文件
public boolean exists()測試此抽象路徑名表示的File是否存在
public String getAbsolutePath()返回此抽象路徑名的絕對路徑名字符串
public String getPath()將此抽象路徑名轉(zhuǎn)換為路徑名字符串
public String getName()返回由此抽象路徑名表示的文件或目錄的名稱
public String[] list()返回此抽象路徑名表示的目錄中的文件和目錄的名稱字符串數(shù)組
public File[] listFiles()返回此抽象路徑名表示的目錄中的文件和目錄的File對象數(shù)組

1.5 遞歸

  1. 遞歸概述: 以編程的角度來看,遞歸指的是方法定義中調(diào)用方法本身的現(xiàn)象

  2. 遞歸解決問題的思路
    • 把一個復(fù)雜的問題層層轉(zhuǎn)化為一個與原問題相似的規(guī)模較小的問題來求解遞歸策略只需少量的程序就可描述出解題過程所需要的多次重復(fù)計算
  3. 遞歸解決問題要找到兩個內(nèi)容
    • 遞歸出口: 否則會出現(xiàn)內(nèi)存溢出
    • 遞歸規(guī)則: 與原問題相似的規(guī)模較小的問題

2 字節(jié)流

2.1 IO流概述和分類

  1. IO流概述

    • IO: 輸入/輸出(Input/Output)
    • 流: 是一種抽象概念,是對數(shù)據(jù)傳輸?shù)目偡Q。也就是說數(shù)據(jù)在設(shè)備間的傳輸稱為流,流的本質(zhì)是數(shù)據(jù)傳輸
    • IO流就是用來處理設(shè)備間數(shù)據(jù)傳輸問題的
      • 常見的應(yīng)用: 文件復(fù)制、文件上傳、文件下載
  2. IO流分類

    • 按照數(shù)據(jù)的流向

      • 輸入流: 讀數(shù)據(jù)
      • 輸出流: 寫數(shù)據(jù)
    • 按照數(shù)據(jù)類型來分
      • 字節(jié)流
      • 字節(jié)輸入流、字節(jié)輸出流
      • 字符流
      • 字符輸入流、字節(jié)輸出流

    一般來說,我們說IO流的分類是按照==數(shù)據(jù)類型==來分的

  3. 那么這兩種流都在什么情況下使用呢?

如果數(shù)據(jù)通過Window自帶的記事本軟件打開,我們還可以==讀懂里面的內(nèi)容==,就使用字符流,否則使用字節(jié)流。如果你不知道該使用哪種類型的流,就使用字節(jié)流

2.2 字節(jié)流寫數(shù)據(jù)

  1. 字節(jié)流抽象基類

    • InputStream: 這個抽象類是表示字節(jié)輸入流的所有類的超類

    • OutputStream: 這個抽象類是表示字節(jié)輸出流的所有類的超類
    • 子類名特點: 類名稱都是以其父類名作為子類名的后綴
  2. FileOutputStream: 文件輸出流用于將數(shù)據(jù)寫入File

    • FileOutputStream(String name): 創(chuàng)建文件輸出流以指定的名稱寫入文件
  3. 使用字節(jié)輸出流寫數(shù)據(jù)的步驟:
    • 創(chuàng)建字節(jié)輸出流對象(調(diào)用系統(tǒng)功能創(chuàng)建了文件,創(chuàng)建字節(jié)輸出流對象,讓字節(jié)輸出流對象指向文件)
    • 調(diào)用字節(jié)輸出流對象的寫數(shù)據(jù)方法
    • 釋放資源(關(guān)閉此文件輸出流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源)

2.3 字節(jié)流寫數(shù)據(jù)的3種方式

方法名說明
void write(int b)將指定的字節(jié)寫入此文件輸出流,一次寫一個字節(jié)數(shù)據(jù)
void write(byte[] b)將b.length字節(jié)從指定的字節(jié)數(shù)組寫入此文件輸出流,一次寫一個字節(jié)數(shù)組數(shù)據(jù)
void write(byte[] b, int off, int len)將len字節(jié)從指定的字節(jié)數(shù)組開始,從偏移量off開始寫入此文件輸出流,一次寫一個字節(jié)數(shù)組的部分數(shù)據(jù)

2.4 字節(jié)流寫數(shù)據(jù)的兩個小問題

  1. 字節(jié)流寫數(shù)據(jù)如何實現(xiàn)換行呢?
    • 寫完數(shù)據(jù)后,加換行符
      • windows: /r/n
      • linux: /n
      • mac: /r
  2. 字節(jié)流寫數(shù)據(jù)如何實現(xiàn)追加寫入呢?
    • public FileOutputStream(String name, boolean append)
    • 創(chuàng)建文件輸出流以指定的名稱寫入文件。如果第二個參數(shù)為true,則字節(jié)將寫入文件的末尾而不是開頭

2.5 字節(jié)流寫數(shù)據(jù)加異常處理

finally: 在異常處理時提供finally塊來執(zhí)行所有清除操作。比如說IO流中的釋放資源

特點: 被finally控制的語句一定會執(zhí)行,除非JVM退出

try {    可能出現(xiàn)異常的代碼;} catch (異常類名 變量名) {    異常的處理代碼;} finally {    執(zhí)行所有清楚操作;}

2.6 字節(jié)流讀數(shù)據(jù)

  1. FilelnputStream: 從文件系統(tǒng)中的文件獲取輸入字節(jié)
    • FileInputStream(String name): 通過打開與實際文件的連接來創(chuàng)建一個FileInputStream,該文件由文件系統(tǒng)中的路徑名name命名
  2. 使用字節(jié)輸入流讀數(shù)據(jù)的步驟:
    1. 創(chuàng)建字節(jié)輸入流對象
    2. 調(diào)用字節(jié)輸入流對象的讀數(shù)據(jù)方法
      1. int read(): 一次讀一個字節(jié)數(shù)據(jù)
      2. int read(byte[] b): 一次讀一個字節(jié)數(shù)組數(shù)據(jù)
    3. 釋放資源

2.7 字節(jié)緩沖流

  1. 字節(jié)緩沖流:

    • BufferOutputStream: 該類實現(xiàn)緩沖輸出流。通過設(shè)置這樣的輸出流,應(yīng)用程序可以向底層輸出流寫入字節(jié),而不必為寫入的每個字節(jié)導致底層系統(tǒng)的調(diào)用
    • BufferedInputStream: 創(chuàng)建BufferedInputStream將創(chuàng)建一個內(nèi)部緩沖區(qū)數(shù)組。當從流中讀取或跳過字節(jié)時,內(nèi)部緩沖區(qū)將根據(jù)需要從所包含的輸入流中重新填充,一次很多字節(jié)
  2. 構(gòu)造方法:

    • 字節(jié)緩沖輸出流: BufferedOutputStream(OutputStream out)
    • 字節(jié)緩沖輸入流: BufferedInputStream(InputStream in)
  3. 為什么構(gòu)造方法需要的是字節(jié)流,而不是具體的文件或者路徑呢?
    • 字節(jié)緩沖流==僅僅提供緩沖區(qū)==,而真正的讀寫數(shù)據(jù)還得依靠基本的字節(jié)流對象進行操作

3 字符流

3.1 為什么會出現(xiàn)字符流

  1. 由于字節(jié)流操作中文不是特別的方便,所以Java就提供字符流

    • ==字符流 = 字節(jié)流+編碼表==
  2. 用字節(jié)流復(fù)制文本文件時,文本文件也會有中文,但是沒有問題,原因是最終底層操作會自動進行字節(jié)拼接成中文,如何識別是中文的呢?
    • 漢字在存儲的時候,無論選擇哪種編碼存儲,第一個字節(jié)都是負數(shù)

3.2 編碼表

  1. 基礎(chǔ)知識:

    • 計算機中儲存的信息都是用==二進制==數(shù)表示的; 我們在屏幕上看到的英文、漢字等字符是二進制數(shù)轉(zhuǎn)換之后
      的結(jié)果
    • 按照某種規(guī)則,將字符存儲到計算機中,稱為==編碼==。反之,將存儲在計算機中的二進制數(shù)按照某種規(guī)則解析顯示出來,稱為==解碼==。這里強調(diào)一下: 按照A編碼存儲,必須按照A編碼解析,這樣才能顯示正確的文本符號,否則就會導致亂碼現(xiàn)象
      • 字符編碼: 就是一套自然語言的字符與二進制數(shù)之間的對應(yīng)規(guī)則(A, 65)
  2. 字符集:

    • 是一個系統(tǒng)支持的所有字符的集合,包括各國家文字、標點符號、圖形符號、數(shù)字等
    • 計算機要準確的存儲和識別各種字符集符號,就需要進行字符編碼,一套字符集必然至少有一套字符編碼。常見字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
  3. ASCIl字符集:

    • ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼): 是基于拉丁字母的一套電腦編碼系統(tǒng),用于顯示現(xiàn)代英語,主要包括控制字符(回車鍵、退格、換行鍵等)和可顯示字符(英文大小寫字符、阿拉伯數(shù)字和西文符號)
    • 基本的ASCII字符集,使用7位表示一個字符,共128字符。ASCII的擴展字符集使用8位表示一個字符,共256字符,方便支持歐洲常用字符。是一個系統(tǒng)支持的所有字符的集合,包括各國家文字、標點符號、圖形符號、數(shù)字等
  4. GBXXX字符集:
    • GB2312: 簡體中文碼表。一個小于127的字符的意義與原來相同,但兩個大于127的字符連在一起時,就表示一個漢字,這樣大約可以組合了包含7000多個簡體漢字,此外數(shù)學符號、羅馬希臘的字母、日文的假名等都編進去了,連在ASCII里本來就有的數(shù)字、標點、字母都統(tǒng)統(tǒng)重新編了兩個字節(jié)長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了
    • ==GBK==: 最常用的中文碼表。是在GB2312標準基礎(chǔ)上的擴展規(guī)范,使用了雙字節(jié)編碼方案,共收錄了21003個漢字,完全兼容GB2312標準,同時支持繁體漢字以及白韓漢字等
    • GB18030: 最新的中文碼表。收錄漢字70244個,采用多字節(jié)編碼,每個字可以由1個、2個或4個字節(jié)組成。支持中國國內(nèi)少數(shù)民族的文字,同時支持繁體漢字以及日韓漢字等
  5. Unicode字符集:
    • 為表達任意語言的任意字符而設(shè)計,是業(yè)界的一種標準,也稱為統(tǒng)一碼、標準萬國碼。它最多使用4個字節(jié)的數(shù)字來表達每個字母、符號,或者文字。有三種編碼方案,UTF-8、UTF-16和UTF32。最為常用的UTF-8編碼
    • ==UTF-8編碼==: 可以用來表示Unicode標準中任意字符,它是電子郵件、網(wǎng)頁及其他存儲或傳送文字的應(yīng)中,優(yōu)先采用的編碼?;ヂ?lián)網(wǎng)工程工作小組(IETF)要求所有互聯(lián)網(wǎng)協(xié)議都必須支持UTF-8編碼。它使用一至四個字節(jié)為每個字符編碼
      • 編碼規(guī)則:
      • 128個US-ASCII字符,只需一個字節(jié)編碼
      • 拉丁文等字符,需要二個字節(jié)編鵒
      • 大部分常用字(含中文),使用三個字節(jié)編碼
      • 其他極少使用的Unicode輔助字符,使用四字節(jié)編碼

==注意: 采用何種規(guī)則編碼,就要采用對應(yīng)規(guī)則解碼,否則就會出現(xiàn)亂碼==

3.3 字符串中的編碼解碼問題

  1. 編碼
    • byte[] getBytes(): 使用平臺的默認字符集將該String編碼為一系列字節(jié),將結(jié)果存儲到新的字節(jié)數(shù)組中
    • byte[] getBytes(String charsetName): 使用指定的字符集將該String編碼為一系列字節(jié),將結(jié)果存儲到新的字節(jié)數(shù)組中
  2. 解碼
    • String(byte[] bytes): 通過使用平臺的默認字符集解碼指定的字節(jié)數(shù)組來構(gòu)造新的String
    • String(byte[] bytes, String charsetName): 通過指定的字符集解碼指定的字節(jié)數(shù)組來構(gòu)造新的String

3.4 字符流中的編碼解碼問題

  1. 字符流抽象基類

    • Reader: 字符輸入流的抽象類
    • Writer: 字符輸出流的抽象類
  2. 字符流中和編碼解碼問題相關(guān)的兩個類:
    • InputStreamReader
    • OutputStreamWriter

3.5 字符流寫數(shù)據(jù)的5種方式

方法名說明
void write(int c)寫一個字符
void write(char[] cbuf)寫入一個字符數(shù)組
void write(char[] cbuf, int off, int len)寫入字符數(shù)組的一部分
void write(String str)寫一個字符串
void write(String str, int off, int len)寫一個字符串的一部分
方法名說明
flush()刷新流,還可以繼續(xù)寫數(shù)據(jù)
close()關(guān)閉流,釋放資源,但是在關(guān)閉之前會先刷新流。一旦關(guān)閉,就不能再寫數(shù)據(jù)

3.6 字符流讀數(shù)據(jù)的2種方式

方法名說明
int read()一次讀一個字符數(shù)據(jù)
int read(char[] cbuf)一次讀一個字符數(shù)組數(shù)據(jù)
  1. FileReader: 用于讀取字符文件的便捷類
    • FileReader(String fileName)
  2. FileWriter: 用于寫入字符文件的便捷類
    • FileWriter(String fileName)

3.7 字符緩沖流

  1. 字符緩沖流:

    • BufferedWriter: 將文本寫入字符輸出流,緩沖字符,以提供單個字符、數(shù)組和字符串的高效寫入,可以指定緩沖區(qū)大小,或者可以接受默認大小。默認值足夠大,可用于大多數(shù)用途
    • BufferedReader: 從字符輸入流讀取文本,緩沖字符,以提供字符、數(shù)組和行的高效讀取,可以指定緩沖區(qū)大小,或者可以使用默認大小。默認值足夠大,可用于大多數(shù)用途
  2. 構(gòu)造方法:
    • BufferedWriter(Writer out)
    • BufferedReader(Reader in)

3.8 字符緩沖流特有功能

  1. BufferedWriter:

    • void newLine(): 寫一行行分隔符,行分隔符字符串由系統(tǒng)屬性定義
  2. BufferedReader:
    • public String readLine(): 讀一行文字。結(jié)果包含行的內(nèi)容的字符串,不包括任何行終止字符,如果流的結(jié)尾已經(jīng)到達,則為null

3.9 IO流小結(jié)

==小結(jié): 字節(jié)流可以復(fù)制任意文件數(shù)據(jù),有4種方式一般采用字節(jié)緩沖流一次讀寫一個字節(jié)數(shù)組的方式==


==小結(jié): 字符流只能復(fù)制文本數(shù)據(jù),有5種方式,一般采用字符緩沖流的特有功能==

3.10 復(fù)制文件的異常處理

  1. try...catch...finally的做法
try {    可能出現(xiàn)異常的代碼;} catch(異常類名 變量名) {    異常的處理代碼;} finally {    執(zhí)行所有清除操作;}
  1. JDK的改進方案
try(定義流對象) {    可能出現(xiàn)異常的代碼;} catch(異常類名 變量名) {    異常的處理代碼;}// 自動釋放資源
  1. JDK9改進方案
// 定義輸入流對象// 定義輸出流對象try (輸入流對象 : 輸出流對象) {    可能出現(xiàn)異常的代碼;} catch(異常類名 變量名) {    異常的處理代碼;}// 自動釋放資源

4 特殊操作流

4.1 標準輸入輸出流

  1. System類中有兩個靜態(tài)的成員變量:

    • public static final InputStream in: 標準輸入流。通常該流對應(yīng)于鍵盤輸入或油由主機環(huán)境或用戶指定的另一個輸入源
    • public static final PrintStream out: 標準輸出流。通常該流對應(yīng)于顯示輸出或由主機環(huán)境或用戶指定的另一個輸出目標
  2. 自己實現(xiàn)鍵盤錄入數(shù)據(jù):

    • BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  3. 寫起來太麻煩,Java就提供了一個類實現(xiàn)鍵盤錄入

    • Scanner sc = new Scanner(System.in);
  4. 輸出語句的本質(zhì): 是一個標準的輸出流
    • PrintStream ps = System.out;
    • PrintStream類有的方法,System.out都可以使用

4.2 打印流

  1. 打印流分類:

    • 字節(jié)打印流: PrintStream
    • 字符打印流: PrintWriter
  2. 打印流的特點:

    • 只負責輸出數(shù)據(jù),不負責讀取數(shù)據(jù)
    • 有自己的特有方法
  3. 字節(jié)打印流
    • PrintStream(String fileName): 使用指定的文件名創(chuàng)建新的打印流
    • 使用繼承父類的方法寫數(shù)據(jù),查看的時候會轉(zhuǎn)碼; 使用自己的特有方法寫數(shù)據(jù),查看的數(shù)據(jù)原樣輸出

4.3 對象序列化流

  1. 對象序列化: 就是將對象保存到磁盤中,或者在網(wǎng)絡(luò)中傳輸對象

    • 這種機制就是使用一個字節(jié)序列表示一個對象,該字節(jié)序列包含: 對象的類型、對象的數(shù)據(jù)和對象中存儲的屬性等信息字節(jié)序列寫到文件之后,相當于文件中持久保存了一個對象的信息
    • 反之,該字節(jié)序列還可以從文件中讀取回來,重構(gòu)對象,對它進行反序列化
  2. 要實現(xiàn)序列化和反序列化就要使用對象序列化流和對象反序列化流:
    • 對象序列化流: ObjectOutputStream
    • 對象反序列化流: ObjectInputStream

4.3.1 對象序列化流

  1. 對象序列化流: ObjectOutputStream

    • 將Java對象的原始數(shù)據(jù)類型和圖形寫入OutputStream。可以使用ObjectInputStream讀取(重構(gòu))對象??梢酝ㄟ^使用流的文件來實現(xiàn)對象的持久存儲。如果流是網(wǎng)絡(luò)套接字流,則可以在另一個主機上或另一個進程中重構(gòu)對象
  2. 構(gòu)造方法:

    • ObjectOutputStream(OutputStream out): 創(chuàng)建一個寫入指定的OutputStream的ObjectOutputStream
  3. 序列化對象的方法:

    • void writeObject(Object obj): 將指定的對象寫入ObjectOutputStream
  4. 注意:
    • 一個對象要想被序列化,該對象所屬的類必須必須==實現(xiàn)Serializable接口==
    • Serializable是一個==標記接口==,實現(xiàn)該接口不需要重寫任何方法

4.3.2 對象反序列化流

  1. 對象反序列化流: ObjectInputStream

    • ObjectInputStream反序列化先前使用ObjectOutputStream編寫的原始數(shù)據(jù)和對象
  2. 構(gòu)造方法:
    • ObjectInputStream(InputStream in): 創(chuàng)建從指定的IlnputStream讀取的ObjectInputStream
  3. 反序列化對象的方法:
    • Object readObject(): 從ObjectInputStream讀取一個對象

4.3.3 問題

  1. 用對象序列化流序列化了一個對象后,假如我們修改了對象所屬的類文件,讀取數(shù)據(jù)會不會出問題呢?
    • 會出問題,拋出==InvalidClassException==異常
  2. 如果出問題了,如何解決呢?
    • 給對象所屬的類加一個==serialVersionUID==
      private static final long serialVersionUID = 42L;
  3. 如果一個對象中的某個成員變量的值不想被序列化,又該如何實現(xiàn)呢?
    • 給該成員變量加==transient==關(guān)鍵字修飾,該關(guān)鍵字標記的成員變量不參與序列化過程

4.4 Properties

  1. Properties概述:

    • 是一個Map體系的集合類
    • Properties可以保存到流中或從流中加載
  2. Properties作為集合的特有方法:
方法名說明
Object setProperty(String key, String value)設(shè)置集合的鍵和值,都是String類型,底層調(diào)用Hashtable方法put
String getProperty(String key)使用此屬性列表中指定的鍵搜索屬性
Set/ stringPropertyNames()從該屬性列表中返回一個不可修改的鍵集,其中鍵及其對應(yīng)的值是字符串
  1. Properties和IO流結(jié)合的方法:
方法名說明
void load(InputStream inStream)從輸入字節(jié)流讀取屬性列表(鍵健和元素對)
==void load(Reader reader)==從輸入字符流讀取屬性列表(鍵和元素對)
void store(OutputStream out, String comments)將此屬性列表(鍵和元素對)寫入此Properties表中,以適合于使用load(InputStream)方法的格式寫入輸出字節(jié)流
==void store(Writer writer, String comments)==將此屬性列表(鍵和元素對)寫入此Properties表中,以適合使用load(Reader)方法的格式寫入輸出字符流