1. 程式人生 > 其它 >Java IO流詳解

Java IO流詳解

File

概述

File類可以定位檔案,進行刪除、獲取文字本身資訊等操作。但是不能讀寫檔案。

  • File類在包java.io.File下、代表作業系統的檔案物件(檔案、資料夾)
  • File類提供了諸如:定位檔案,獲取檔案本身的資訊、刪除檔案、建立檔案(資料夾)等功能

建立File物件

// 根據檔案路徑建立檔案物件
public File(String pathname)
// 從父路徑和子路徑名字字串建立檔案物件
public File(String parent, String child)
// 根據父路徑對應檔案物件和子路徑名字串建立檔案物件
public File(File parent, String child)

File.separator路徑連線符,用於拼接路徑

new File("D:" + File.separator + "data" + File.separator + "1.txt")

常用API

獲取檔案資訊

public boolean isDirectory()

測試此抽象路徑名錶示的File是否為資料夾

public boolean isFile()

測試此抽象路徑名錶示的File是否為檔案

public boolean exists()

測試此抽象路徑名錶示的File是否存在

public String getAbsolutePath()

返回此抽象路徑名的絕對路徑名字串

public String getPath()

將此抽象路徑名轉換為路徑名字串

public String getName()

返回由此抽象路徑名錶示的檔案或資料夾的名稱

public long lastModified()

返回檔案最後修改的時間毫秒值

建立、刪除檔案

public boolean createNewFile()

建立一個新的空的檔案

public boolean mkdir()

只能建立一級資料夾

public boolean mkdirs()

可以建立多級資料夾

public boolean delete( )

刪除由此抽象路徑名錶示的檔案或空資料夾

delete方法直接刪除不走回收站;如果刪除的是-一個檔案,且檔案沒有被佔用則直接刪除。
delete方法預設只能刪除空資料夾。

遍歷檔案

public String[] list()

獲取當前目錄下所有的"一級檔名稱"到一個字串陣列中去返回。

public File[] listFiles()(常用)

獲取當前目錄 下所有的"一-級檔案物件"到一個檔案物件陣列中去返回(重點)

listFiles方法注意事項:

  • 當呼叫者不存在時,返回null
  • 當呼叫者是一個檔案時,返回null
  • 當呼叫者是一個空資料夾時,返回一個長度為0的陣列
  • 當呼叫者是一個有內容的資料夾時, 將裡面所有檔案和資料夾的路徑放在File陣列中返回
  • 當呼叫者是一個有隱藏檔案的資料夾時,將裡面所有檔案和資料夾的路徑放在File陣列中返回,包含隱藏內容

字符集

ASCII字符集

ASCII(American Standard Code for Information Interchange, 美國資訊交換標準程式碼):包括了數字、英文、符號.
ASCII使用1個位元組儲存一個字元,一個位元組是8位,總共可以表示128個字元資訊,對於英文,數字來說是夠用的。

01100001 = 97 => a
01100010 = 98 => b

GBK

window系統預設的碼錶。相容ASCI碼錶,也包含了幾萬個漢字,並支援繁體漢字以及部分日韓文字。

注意: GBK是中國的碼錶,一箇中文以兩個位元組的形式儲存。但不包含世界上所有國家的文字。

Unicode碼

unicode (又稱統一碼、萬國碼、單一碼)是電腦科學領域裡的一項業界字元編碼標準

容納世界上大多數國家的所有常見文字和符號

由於Unicode會先通過UTF-8, UTF-16, 以及UTF-32的編碼成二進位制後再儲存到計算機,其中最為常見的就是UTF-8

注意

  • Unicode是萬國碼, 以UTF-8編碼後一箇中文一般以三個位元組的形式儲存。
  • UTF-8也要相容ASCII編碼表。
  • 技術人員都應該使用UTF-8的字符集編碼。
  • 編碼前和編碼後的字符集需要一致,否則會出現中文亂碼。

String編碼

byte[] getBytes()

使用平臺的預設字符集將該String編碼為一系列位元組,將結果儲存到新的位元組陣列中

byte[] getBytes(String charsetName)

使用指定的字符集將該String編碼為-系列位元組,將結果儲存到新的位元組陣列中

String解碼

String(byte[] bytes)

通過使用平臺的預設字符集解碼指定的位元組陣列來構造新的String

String(byte[] bytes, String charsetName)

通過指定的字符集解碼指定的位元組陣列來構造新的String

IO流

IO流概述

  • I表示intput, 是資料從硬碟檔案讀入到記憶體的過程,稱之輸入,負責讀。
  • O表示output, 是記憶體程式的資料從記憶體到寫出到硬碟檔案的過程,稱之輸出,負責寫。

IO流四大類

位元組輸入流

以記憶體為基準,來自磁碟檔案/網路中的資料以位元組的形式讀入到記憶體中去的流

位元組輸出流

以記憶體為基準,把記憶體中的資料以位元組寫出到磁碟檔案或者網路中去的流

字元輸入流

以記憶體為基準,來自磁碟檔案/網路中的資料以字元的形式讀入到記憶體中去的流

字元輸出流

以記憶體為基準,把記憶體中的資料以字元寫出到磁碟檔案或者網路介質中去的流

位元組流

FileInputStream

將磁碟檔案、網路中的資料以位元組的形式讀取到記憶體中去

構造器

// 建立位元組輸入流管道與原始檔物件接通
public FileInputStream(File file)
// 建立位元組輸入流管道 與原始檔路徑接通
public FileInputStream(String pathname)

方法

// 每次讀取一個位元組返回,如果位元組已經沒用可讀的返回-1
public int read()
// 每次讀取一個位元組陣列返回,如果位元組已經沒有可讀的返回-1,返回的讀取陣列的長度
public int read(byte[] buffer)

位元組流讀取中文亂碼問題

因為位元組輸入流是按照位元組的方式讀取的,而中文是雙位元組或者三位元組的,可能會使得中文位元組從中截斷以造成中文亂碼的問題。

解決

  • 一次性讀取檔案的全部位元組(但資料過大可能造成記憶體溢位)

  • 官方提供了一個API可以直接把檔案的全部數讀取到一個位元組陣列中

    public byte[] readAllBytes() throws IOException
    

FileOutputStream

把記憶體中的資料以位元組寫出到磁碟檔案或者網路中去的流

構造器

public FileOutputStream(String name)
// append為true則追加的檔案的末尾,為false則覆寫檔案
public FileOutputStream(String name, boolean append)

public FileOutputStream(File file)
public FileOutputStream(File file, boolean append)

方法

public void write(int a)
// 寫一個位元組出去
public void write(byte[] buffer)
// 寫一個位元組陣列出去
public void write(byte[] buffer ,int pos,int len)
// 寫一個位元組陣列的一部分出去。

流的關閉與重新整理

// 重新整理流,還可以繼續寫資料,將在緩衝區的資訊重新整理到檔案或網路中
flush()
// 關閉流,釋放資源,但是在關閉之前線重新整理流。一旦關閉就不再寫資料
close()

資源釋放的方式

try-cath-finally

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

特點:被finally控制的語句最終一定會執行, 除非JVM退出

try {

} catch (Exception e) {

} finally {

}

此方式多用於JDK7以前,JDK7和JDK9做了改進

// JDK7 資源用完會自動釋放
try (定義流物件) {

} catch () {

}
// JDK9 資源用完會自動釋放
定義流物件
try (流物件) {
    
} catch () {
    
}

轉換流

位元組流和字元流之間的橋樑

InputStreamReader

位元組到字元橋樑

構造器

// 預設字符集
public InputStreamReader(InputStream in)
// 指定字符集編碼
public InputStreamReader(InputStream in, String charsetName)

方法

public int read()
// 每次讀取一個字元返回,如果字元已經沒有可讀的返回-1
public int read(char[] buffer)
// 每次讀取一個字元陣列,返回讀取的字元數,如果字元已經沒有可讀的返回-1

示例:位元組流System.In轉為字元流

public static void main(String[] args) throws IOException {
    //位元組流-->字元流
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter bw = new BufferedWriter(new FileWriter("is2.txt"));
    String line = null;
    while((line = br.readLine())!=null){
        if("over".equals(line)){
            break;
        }
        bw.write(line);
        bw.newLine();
        bw.flush();         
    }
    bw.close();
    br.close();
}

OutputStreamWriter

字元到位元組的橋樑

構造器

// 預設字符集
public OutputStreamWriter(OutputStream out)
// 指定字符集編碼
public OutputStreamWriter(OutputStream out, String charsetName)

方法

void write(int c)
void write(char[] cbuf)
void write(char[] cbuf, int off, int len)

void write(String str)
void write(String str, int off, int len)
void write(int c)
// 重新整理流,還可以繼續寫資料,將在緩衝區的資訊重新整理到檔案或網路中
flush()
// 關閉流,釋放資源,但是在關閉之前線重新整理流。一旦關閉就不再寫資料
close()

示例:字元流轉為位元組流System.out

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("is2.txt"));
    //字元流-->位元組流
   	BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    String line = null;
    while ((line = br.readLine())!=null) {
        bw.write(line);
        bw.newLine();
        bw.flush();
    }
    bw.close();
    br.close();
}

字元流

FileReader

來自磁碟檔案/網路中的資料以字元的形式讀入到記憶體中去的流

FileReader繼承自輸入轉換流,實際與輸入轉換流一致,並未實現更多的方法

不過提供了更多的構造器方法

public class FileReader extends InputStreamReader

構造器

不指定字符集的時候,就會使用預設的字符集來讀取資料

// 構造方法與FileInputStream類似,多出了一個字符集引數
public FileReader(String fileName)
public FileReader(String fileName, Charset charset)
public FileReader(File file)
public FileReader(File file, Charset charset)

方法

public int read()
// 每次讀取一個字元返回,如果字元已經沒有可讀的返回-1
public int read(char[] buffer)
// 每次讀取一個字元陣列,返回讀取的字元數,如果字元已經沒有可讀的返回-1

FileWriter

把記憶體中的資料以字元寫出到磁碟檔案或者網路介質中去的流

FileWriter繼承自轉換流,實際與輸出轉換流一致,並未實現更多的方法

不過提供了更多的構造器方法

public class FileWriter extends OutputStreamWriter 

構造器

// append: 可追加到檔案末尾
// charset: 字元編碼集

public FileWriter(File file)
public FileWriter(File file, boolean append)
public FileWriter(String fileName, Charset charset)
public FileWriter(String fileName, Charset charset, boolean append)

public FileWriter(String filepath)
public FileWriter(String filepath, boolean append)
public FileWriter(File file, Charset charset)
public FileWriter(File file, Charset charset, boolean append)

方法

void write(int c)
void write(char[] cbuf)
void write(char[] cbuf, int off, int len)

void write(String str)
void write(String str, int off, int len)
void write(int c)
// 重新整理流,還可以繼續寫資料,將在緩衝區的資訊重新整理到檔案或網路中
flush()
// 關閉流,釋放資源,但是在關閉之前線重新整理流。一旦關閉就不再寫資料
close()

緩衝流

緩衝流也稱為高效流,或者高階流。之前學習的位元組流可以稱為原始流。

作用:緩衝流自帶緩衝區、可以提高原始位元組流、字元流讀寫資料的效能。

BufferredInputStream

位元組緩衝輸入流:提高位元組輸入流讀取資料的效能,讀寫功能無變化

構造器

將低階的位元組輸入流包裝成一個高階的緩衝位元組輸入流

// 預設緩衝區8kb
public BufferedInputStream(InputStream in)
// 指定buffer的大小
public BufferedInputStream(InputStream in, int size)

BufferedOutputStream

位元組緩衝輸出流:提高位元組輸出流讀取資料的效能,讀寫功能無變化

構造器

將低階的位元組輸出流包裝成一個高階的緩衝位元組輸出流

// 預設緩衝區8kb
public BufferedOutputStream(OutputStream out)
// 指定buffer的大小
public BufferedOutputStream(OutputStream out, int size)

BufferedReader

字元緩衝輸入流:提高字元輸入流讀取資料的效能,除此之外多了按照行讀取資料的功能

構造器

把低階的字元輸入流包裝成一個高階的緩衝字元輸入流管道,從而提高字元輸入流讀資料的效能

// 預設緩衝區8kb
public BufferedReader(Reader in) 
// 指定buffer的大小
public BufferedReader(Reader in, int sz)

新增API

// 讀取一行資料返回,如果讀取沒有完畢,無行可讀返回null
public String readline()

BufferedWriter

字元緩衝輸出流:提高字元輸出流寫資料的效能,除此之外多了換行功能

構造器

// 預設緩衝區8kb
public BufferedWriter(Writer out)
// 指定buffer的大小
public BufferedWriter(Writer out, int sz)

新增API

// 換行操作
public void newLine()

序列化

物件序列化

ObjectOutputStream

把記憶體中的物件儲存到磁碟檔案中去

構造器

// 將低階的字元輸出流包裝成高階的物件位元組輸出流
public ObjectOutputStream(OutputStream out)

方法

// 把物件寫出到物件序列化流的檔案中去
public final void writeObject(Object obj)

物件反序列化

ObjectInputStream

把儲存到磁碟檔案中去的物件資料恢復到記憶體中

構造器

// 將低階的字元輸入流包裝成高階的物件位元組輸入流
public ObjectInputStream(InputStream in)

方法

// 把磁碟檔案中的物件資料恢復成記憶體中的物件
public Object readObject()

列印流

列印流可以實現方便、高效的列印資料到檔案中去

可以實現列印什麼資料就是什麼資料

PrintStream

核心構造器

private PrintStream(boolean autoFlush, OutputStream out) {
    super(out);
    this.autoFlush = autoFlush;
    this.charOut = new OutputStreamWriter(this, charset);
    this.textOut = new BufferedWriter(charOut);
}

PrintStream會構建三個流

  • 位元組輸出流

  • 字元轉換輸出流

  • 字元緩衝輸出流

可以同時實現列印位元組和字元

位元組輸出使用 FileOutputStream流實現

字元輸出使用 BufferedWriter流實現

構造器

// 提供了三種構造器
// 檔名 檔案物件 位元組輸出流
public PrintStream(OutputStream out)
public PrintStream(OutputStream out, boolean autoFlush)
public PrintStream(OutputStream out, boolean autoFlush, Charset charset)

public PrintStream(String fileName)
public PrintStream(String fileName, Charset charset)
    
public PrintStream(File file)
public PrintStream(File file, Charset charset)

方法

// 可列印任意型別資料
// 前提是型別重寫了toString()方法
// int float double boolean等基本型別會使用包裝型別返回string 
public void print(XXX xxx)
public void println(XXX xxx)

PrintWriter

核心構造器

public PrintWriter(OutputStream os)
// 列印流直接通向位元組輸出流管道
public PrintWriter (Writer w)
// 列印流直接通向字元輸出流管道
public PrintWriter (File f)
// 列印流直接通向檔案物件
public PrintWriter (String filepath)
// 列印流直接通向檔案路徑

方法

// 可列印任意型別資料
// 前提是型別重寫了toString()方法
// int float double boolean等基本型別會使用包裝型別返回string 
public void print(XXX xxx)
public void println(XXX xxx)

對比

  • 列印資料功能上是一模一樣的,使用方便,效能高效
  • PrintStream繼承自位元組輸出流,支援寫位元組資料
  • PrintWriter繼承自字元輸出流Writer,支援寫字元資料

列印流重定向

可以將輸出語句的列印位置改到檔案

PrintStream ps = new PrintStream("檔案地址")
System.setOut(ps);

Properties

實際是一個Map集合

核心功能

  • Properties代表的是一個屬性檔案,可以把自己物件中的鍵值對資訊存入到一個屬性檔案中去
  • 屬性檔案:字尾樹.properties結尾的檔案,裡面的內容都是key=value,後續做系統配置資訊

方法

// 從輸入位元組流讀取屬性列表(鍵和元素對)
void load(InputStream inStream)
// 從輸入字元流讀取屬性列表(鍵和元素對)
void load(Reader reader)

// 將此屬性列表(鍵和元素對)寫入此Properties表中,以適合於使用load(InputStream)方法的格式寫入輸出位元組流
void store (OutputStream out, String comments)

// 將此屬性列表(鍵和元素對)寫入此Properties表中,以適合使用load(Reader)方法的格式寫入輸出字元流
void store(Writer writer, String comments)

// 儲存鍵值對(put)
public object setProperty(String key, String value)

// 使用此屬性列表中指定的鍵搜尋屬性值(get)
public String getProperty(String key)

// 所有鍵的名稱的集合(keySet()
public Set<String> stringPropertyNames()

參考

  1. Java入門基礎視訊教程,java零基礎自學首選黑馬程式設計師Java入門教程(含Java專案和Java真題)_嗶哩嗶哩_bilibili
  2. Java學習的第二十三天(JavaSE最終篇_IO流之字元流_轉換流和緩衝流)_飛奔的嗨少的部落格-CSDN部落格