JavaSE中IO文件操作詳細(xì)指南
一、文件
1.1 文件的概念
在操作系統(tǒng)中會將“硬盤設(shè)備”和“軟件資源”都抽象成文件。
在生活中提到的文件大多指硬盤的文件(像c盤里面的文件),就是硬盤上的數(shù)據(jù)抽象而成的。
1.2 文件的操作
在計算機(jī)上文件是由操作系統(tǒng)提供的“文件系統(tǒng)”來組織管理的,操作系統(tǒng)使用“目錄”(也就是常說的文件夾)來管理文件的。目錄是一種樹形結(jié)構(gòu)
1.3 路徑
- 絕對路徑:就是以C盤D盤(C: D:)這種盤符開頭的路徑。如"E:\植物大戰(zhàn)僵尸"。
- 相對路徑:此時需要先指定一個基準(zhǔn)目錄,然后看通過什么樣的路徑來到指定文件,這個路徑就是相對路徑,用點開頭。此時用一個點表示當(dāng)前目錄,兩個點表示當(dāng)前目錄上一級目錄。
舉例:
假如我們要找“E:\植物大戰(zhàn)僵尸\pvzHE"目錄下的"fonts"文件。
- 如果我們當(dāng)前在“E:\植物大戰(zhàn)僵尸\pvzHE"目錄下,直接使用“.\fonts”
- 如果我們在“E:\植物大戰(zhàn)僵尸”目錄下,使用“.\pvzHE\fonts”
- 如果我們在"E:\植物大戰(zhàn)僵尸\pvzHE\新建文件夾"目錄下,使用“…\fonts”
不同場景下的基準(zhǔn)目錄:
- 在命令行操作,當(dāng)前目錄就是基準(zhǔn)目錄。
- 在idea操作項目目錄就是基準(zhǔn)目錄(打jar包等另行考慮)。
- 在圖形化工具上就要看實際情況了。
1.4 文件分類
在編程角度上將文件分為兩類:
- 文本文件:文件中保存的都是字符串,保存的都是合法的字符(合法的字符就是符合當(dāng)前字符集編碼的字符)。
- 二進(jìn)制文件:文件中保存的僅僅是二進(jìn)制數(shù)據(jù)。
二、Java中的文件元信息、路徑操作
Java 中通過 java.io.File 類來對一個文件(包括目錄)進(jìn)行抽象的描述。
2.1 屬性
修飾符及類型 | 屬性 | 說明 |
---|---|---|
static String | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,String 類型的表示 |
static char | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,char 類型的表示 |
2.2 構(gòu)造方法
簽名 | 說明 |
---|---|
File(File parent, String child) | 根據(jù)父目錄 + 孩子文件路徑,創(chuàng)建一個新的 File 實例 |
File(String pathname) | 根據(jù)文件路徑創(chuàng)建一個新的 File 實例,路徑可以是絕對路徑或者相對路徑 |
File(String parent, String child) | 根據(jù)父目錄 + 孩子文件路徑,創(chuàng)建一個新的 File 實例,父目錄用路徑表示 |
2.3 方法
2.3.1 文件路徑
修飾符及返回值類型 | 方法簽名 | 說明 |
---|---|---|
String | getParent() | 返回 File 對象的父目錄文件路徑 |
String | getName() | 返回 FIle 對象的純文件名稱 |
String | getPath() | 返回 File 對象的文件路徑 |
String | getAbsolutePath() | 返回 File 對象的絕對路徑 |
String | getCanonicalPath() | 返回 File 對象的修飾過的絕對路徑 |
2.3.2 文件判斷
修飾符及返回值類型 | 方法簽名 | 說明 |
---|---|---|
boolean | exists() | 判斷 File 對象描述的文件是否真實存在 |
boolean | isDirectory() | 判斷 File 對象代表的文件是否是一個目錄 |
boolean | isFile() | 判斷 File 對象代表的文件是否是一個普通文件 |
boolean | canRead() | 判斷用戶是否對文件有可讀權(quán)限 |
boolean | canWrite() | 判斷用戶是否對文件有可寫權(quán)限 |
2.3.3 文件創(chuàng)建刪除
修飾符及返回值類型 | 方法簽名 | 說明 |
---|---|---|
boolean | createNewFile() | 根據(jù) File 對象,自動創(chuàng)建一個空文件。成功創(chuàng)建后返回 true |
boolean | delete() | 根據(jù) File 對象,刪除該文件。成功刪除后返回 true |
void | deleteOnExit() | 根據(jù) File 對象,標(biāo)注文件將被刪除,刪除動作會到JVM 運(yùn)行結(jié)束時才會進(jìn)行 |
2.3.4 其他操作
修飾符及返回值類型 | 方法簽名 | 說明 |
---|---|---|
String[ ] | list() | 返回 File 對象代表的目錄下的所有文件名 |
File[ ] | listFiles() | 返回 File 對象代表的目錄下的所有文件,以 File 對象表示 |
boolean | mkdir() | 創(chuàng)建 File 對象代表的目錄 |
boolean | mkdirs() | 創(chuàng)建 File 對象代表的目錄,如果必要,會創(chuàng)建中間目錄 |
boolean | renameTo(Filedest) | 進(jìn)行文件改名,也可以視為我們平時的剪切、粘貼操作 |
三、文件讀寫操作
在Java中對文件的讀寫操作使用流對象(stream)
3.1 流(Stream)
在標(biāo)準(zhǔn)庫中提供的文件讀寫操作的類有很多,但可以分為兩類。
3.1.1 字節(jié)流
字節(jié)流對應(yīng)著二進(jìn)制文件,每次讀寫的最小單位都是字節(jié)(Byte)。
字節(jié)流提供了兩個父類(InputStream)(OutputStream)來供繼承。
3.1.1.1 InputStream
InputStream在源碼中是一個抽象類,不能直接new對象。提供了一個子類FileInputStream。
類需要傳文件路徑,如果文件沒找到還會拋出FileNotFoundException異常。
方法簡介
返回值 | 方法簽名 | 說明 |
---|---|---|
int | read() | 讀取一個字節(jié)的數(shù)據(jù),返回 -1 代表已經(jīng)完全讀完了 |
int | read(byte[ ] b) | 最多讀取 b.length 字節(jié)的數(shù)據(jù)到 b 中,返回實際讀到的數(shù)量;-1 代表以及讀完了 |
int | read(byte[ ] b, int off, int len) | 最多讀取 len - off 字節(jié)的數(shù)據(jù)到 b 中,放在從 off 開始,返回實際讀到的數(shù)量;-1 代表以及讀完了 |
void | close() | 關(guān)閉字節(jié)流 |
3.1.1.2 OutputStream
默認(rèn)打開一個文件會先清空,要繼續(xù)寫不清空在創(chuàng)建對象時傳入true作為第二個參數(shù)。
OutputStream在源碼中是一個抽象類,不能直接new對象。提供了一個子類FileOutputStream。
類需要傳文件路徑,如果文件沒找到還會拋出FileNotFoundException異常。
方法
返回值 | 方法簽名 | 說明 |
---|---|---|
void | write(int b) | 寫入要給字節(jié)的數(shù)據(jù) |
void | write(byte[ ] b) | 將 b 這個字符數(shù)組中的數(shù)據(jù)全部寫入 os 中 |
int | write(byte[ ] b, int off, int len) | 將 b 這個字符數(shù)組中從 off 開始的數(shù)據(jù)寫入 os 中,一共寫 len 個 |
void | close() | 關(guān)閉字節(jié)流 |
void | flush() | 重要:我們知道 I/O 的速度是很慢的,所以,大多的 OutputStream 為了減少設(shè)備操作的次數(shù),在寫數(shù)據(jù)的時候都會將數(shù)據(jù)先暫時寫入內(nèi)存的一個指定區(qū)域里,直到該區(qū)域滿了或者其他指定條件時才真正將數(shù)據(jù)寫入設(shè)備中,這個區(qū)域一般稱為緩沖區(qū)。但造成一個結(jié)果,就是我們寫的數(shù)據(jù),很可能會遺留一部分在緩沖區(qū)中。需要在最后或者合適的位置,調(diào)用 flush(刷新)操作,將數(shù)據(jù)刷到設(shè)備中。 |
3.1.2 字符流
字符流對應(yīng)著文本文件,每次讀寫的最小單位是字符(根據(jù)當(dāng)前字符集來,一個中文字符在utf8就是3字節(jié),GBK就是兩字節(jié))。
字符流就相當(dāng)于對字節(jié)流進(jìn)行了一個封裝,自動幫我們把字節(jié)流中相鄰幾個字節(jié)轉(zhuǎn)換成字符。
字符流提供了兩個父類(Reader)(Writer)來供繼承。
3.1.2.1 Reader
Reader在源碼中是一個抽象類,不能直接new對象。提供了一個子類FileReader。
FileReader類需要傳文件路徑,如果文件沒找到還會拋出FileNotFoundException異常。
Reader中讀取字符常用是read方法,都會拋出IOException異常,介紹常用3種。
返回值 | 分法簽名 | 說明 |
---|---|---|
int | read() | 讀取一個字符,讀取到返回ASCII值或者字符集編碼值,沒讀取到返回-1 |
int | read(char[ ] cbuf) | 讀取多個字符,盡量將cbuf數(shù)組填滿,返回讀取到的字符個數(shù),如果讀完文件返回-1 |
int | read(char[ ] cbuf, int off, int len) | l最多讀len-off個,從數(shù)組off下標(biāo)開始儲存,返回讀到的個數(shù),如果讀完文件返回-1 |
返回值說明:
int作為返回值時,返回的是一個2字節(jié)表示的,這時因為在Java中char類型是Unicode編碼,而String是由utf8編碼(String的編碼集可改)。
創(chuàng)建了一個Reader對象要釋放:對象名.close();
主要釋放的是文件描述符表(在進(jìn)程介紹PCB的主要屬性),文件描述符表里面主要用順序表(數(shù)組)來儲存,如果一直不釋放,里面數(shù)組被占滿就會發(fā)生內(nèi)存泄露。
但是如果直接就這么寫,那如果上面代碼拋出異常,就執(zhí)行不到close,改進(jìn)方法:
- try-finally處理:
Reader reader = new FileReader("d:/test.txt"); try { int n = reader.read(); } finally { reader.close(); }
- try with resource
在定義對象時放入,出了try語句就會自動調(diào)用類實現(xiàn)的close方法(必須是實現(xiàn)了closeable接口的)。
try( Reader reader = new FileReader("d:/test.txt") ) { int n = reader.read(); }
3.1.2.2 Writer
默認(rèn)打開一個文件會先清空,要繼續(xù)寫不清空在創(chuàng)建對象時傳入true作為第二個參數(shù)。
InputStream在源碼中是一個抽象類,不能直接new對象。提供了一個子類FileInputStream。
類需要傳文件路徑,如果文件沒找到還會拋出IOException異常。
方法
返回值 | 方法簽名 | 說明 |
---|---|---|
void | write(int c) | 寫入要給文件的數(shù)據(jù) |
void | write(char[ ] cbuf) | 將 cbuf 這個字符數(shù)組中的數(shù)據(jù)全部寫入 os 中 |
int | write(byte[ ] cbuf, int off, int len) | 將 cbuf 這個字符數(shù)組中從 off 開始的數(shù)據(jù)寫入 os 中,一共寫 len 個 |
void | write(String str) | 將 str 這個字符串中的數(shù)據(jù)全部寫入 os 中 |
void | write(String str, int off, int len) | 將 str 這個字符串中的數(shù)據(jù)從 off 開始的數(shù)據(jù)寫入 os 中,一共寫 len 個 |
void | close() | 關(guān)閉字節(jié)流 |
void | flush() | 重要:我們知道 I/O 的速度是很慢的,所以,大多的 OutputStream 為了減少設(shè)備操作的次數(shù),在寫數(shù)據(jù)的時候都會將數(shù)據(jù)先暫時寫入內(nèi)存的一個指定區(qū)域里,直到該區(qū)域滿了或者其他指定條件時才真正將數(shù)據(jù)寫入設(shè)備中,這個區(qū)域一般稱為緩沖區(qū)。但造成一個結(jié)果,就是我們寫的數(shù)據(jù),很可能會遺留一部分在緩沖區(qū)中。需要在最后或者合適的位置,調(diào)用 flush(刷新)操作,將數(shù)據(jù)刷到設(shè)備中。 |
3.2 字節(jié)流字符流轉(zhuǎn)換
使用Scanner工具類去讀取文件中的字符。
try(InputStream inputStream = new FileInputStream("D:/test.txt")) { Scanner scanner = new Scanner(inputStream); String s = scanner.next(); }
使用PrintWriter工具類去寫入文件中的字符。
try(OutputStream outputStream = new FileOutputStream("D:/test.txt",true)) { PrintWriter printWriter = new PrintWriter(outputStream); printWriter.println(); }
四、自定義快讀類
自定義快讀類來解決我們做算法題的時候由于數(shù)據(jù)量過大的時候引起的超時問題。
4.1 自定義快速讀入
我們使用Scanner去讀IO設(shè)備文件,,而我們現(xiàn)在使用BufferedReader來開辟一個內(nèi)存緩沖區(qū),在內(nèi)存中拿數(shù)據(jù)比IO設(shè)備要快得多。
步驟:
- 字節(jié)流轉(zhuǎn)變?yōu)樽址?,在存入?nèi)存緩沖區(qū)中。
BufferedReader bf = new BufferedReader(new InputStreamReader(system.in));
- 字符串裁剪對象,拿到內(nèi)存緩沖區(qū)的字符串的必要對象。
StringTokenizer st = new StringTokenizer("");
- 詳解next方法:相當(dāng)于在內(nèi)存緩沖區(qū)中拿一行數(shù)據(jù),使用while循環(huán)來處理多行輸入。
String next() throws IOException { while(!st.hasMoreTokens()) { st = new StringTokenizer(bf.readLine()); } return st.nextToken(); }
- 其他直接返回對應(yīng)的parse轉(zhuǎn)換就行。
類代碼:
import java.util.StringTokenizer; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; class Read { StringTokenizer st = new StringTokenizer(""); BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); String next() throws IOException { while(!st.hasMoreTokens()) { st = new StringTokenizer(bf.readLine()); } return st.nextToken(); } String nextLine() throws IOException { return bf.readLine(); } int nextInt() throws IOException { return Integer.parseInt(next()); } long nextLong() throws IOException { return Long.parseLong(next()); } double nextDouble() throws IOException { return Double.parseDouble(next()); } float nextFloat() throws IOException { return Float.parseFloat(next()); } }
4.2 自定義快速輸出
跟自定義一樣的優(yōu)化方式。
public static PrintWriter out = new PrintWriter(new BufferedWriter(new OutPutStreamWriter(System.out)))
使用之后就直接 out.輸出方法,輸出方法與System.out一樣。
總結(jié)
到此這篇關(guān)于JavaSE中IO文件操作的文章就介紹到這了,更多相關(guān)JavaSE IO文件操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot應(yīng)用Docker化的步驟詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot應(yīng)用Docker化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04MyBatis中模糊查詢使用CONCAT('%',#{str},'%')出錯的解
這篇文章主要介紹了MyBatis中模糊查詢使用CONCAT('%',#{str},'%')出錯的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01詳解SpringBoot定制@ResponseBody注解返回的Json格式
這篇文章主要介紹了詳解SpringBoot定制@ResponseBody注解返回的Json格式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11