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()
參考
- Java入門基礎視頻教程,java零基礎自學首選黑馬程序員Java入門教程(含Java項目和Java真題)_嗶哩嗶哩_bilibili
- Java學習的第二十三天(JavaSE最終篇_IO流之字符流_轉換流和緩衝流)_飛奔的嗨少的博客-CSDN博客

