Java文件操作與IO流詳解(File類+字節(jié)流+字符流)
一、文件的概念
狹義的文件:保存在硬盤上的文件。
廣義的文件:操作系統(tǒng)進(jìn)行管理的一種機(jī)制,很多軟件/硬件資源抽象成“文件”來進(jìn)行表示。
注:當(dāng)前這篇文章主要討論狹義文件。
下面這張圖片里面有一些文件,在計算機(jī)專業(yè)術(shù)語中稱做:目錄

一臺計算機(jī)中能保存很多文件,區(qū)分/識別一個文件就需要通過文件的路徑來進(jìn)行識別。
二、路徑
路徑: 定位到文件的一系列過程。在計算機(jī)中目錄套目錄,形成了樹形結(jié)構(gòu),從樹根開始,到最終的文件,都需要經(jīng)過哪些目錄,把這些目錄記錄下來,就構(gòu)成了路徑。
斜杠 / : 在主流的操作系統(tǒng)中都是使用/來分割的。但是Windows是例外,Windows / 和 \(反斜杠 ) 都支持(Windows默認(rèn)使用\)
2.1絕對路徑
從根節(jié)點(diǎn)開始,逐級表示出來
示例:找E盤LX2下的test.txt文件的路徑

絕對路為: E:\前端開發(fā)\實驗二\LX2\test.txt
2.2相對路徑
需要明確一個基準(zhǔn)路徑,以這個基準(zhǔn)來找對應(yīng)的文件。
示例:找E盤LX2下的test.txt文件的相對路徑

假設(shè)基準(zhǔn)為:E:\前端開發(fā)\實驗二\LX2,那么test.txt的相對路徑就是:./test.txt (.表示當(dāng)前所在的目錄位置)
假設(shè)基準(zhǔn)為:E:\前端開發(fā)\實驗二,那么test.txt的相對路徑就是:./LX2/test.txt
假設(shè)基準(zhǔn)為:E:\前端開發(fā)\實驗二\LX2\photo,那么test.txt的相對路徑就是:…/test.txt(..表示當(dāng)前路徑的上一層路徑)
如果在代碼中寫一個相對路徑,基準(zhǔn)路徑是誰呢?
不確定,取決于程序的運(yùn)行方式,在IDEA中直接運(yùn)行,基準(zhǔn)路徑就是項目的目錄,如果打一個jar包,單獨(dú)運(yùn)行jar包,當(dāng)前在哪個目錄下執(zhí)行運(yùn)行命令(java -jar jar包名),基準(zhǔn)目錄就是哪個目錄。
三、文件的種類
從開發(fā)的角度把文件分為兩大類
- 1.文本文件
- 2.二進(jìn)制文件
在實際開發(fā)中判斷一個文件是否是文本,最簡單的方法是用記事本打開,打開之后不是亂碼,能看懂文本,就是文本文件,如果是亂碼,看不懂,就是二進(jìn)制文件。
示例:二進(jìn)制文件 圖片,音頻,視頻,可執(zhí)行程序,word,docx 都是典型的二進(jìn)制文件。
示例:文本文件 txt純文本, .java, .c都是典型的文本文件。
四、JAVA中操作文件
Java中通過java.io.File 類來對?個?件(包括目錄)進(jìn)行抽象的描述。注意,有File對象,并不代表真實存在該文件。
4.1 File類
File類是 Java 標(biāo)準(zhǔn)庫(java.io 包)中定義的一個類。它用來表示文件或目錄的路徑,并提供操作這些路徑的方法。
1. 屬性表格
| 修飾符及類型 | 屬性 | 說明 |
|---|---|---|
static String | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,String 類型的表示 |
static char | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,char 類型的表示 |
參數(shù)String文件的路徑使用絕對路徑/相對路徑均可。
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 實例,父目錄用路徑表示 |
3. 方法表格
| 修飾符及返回值類型 | 方法簽名 | 說明 |
|---|---|---|
String | getParent() | 返回 File 對象的父目錄文件路徑 |
String | getName() | 返回 File 對象的純文件名稱 |
String | getPath() | 返回 File 對象的文件路徑 |
String | getAbsolutePath() | 返回 File 對象的絕對路徑 |
String | getCanonicalPath() | 返回 File 對象的修飾過的絕對路徑 |
boolean | exists() | 判斷 File 對象描述的文件是否真實存在 |
boolean | isDirectory() | 判斷 File 對象代表的文件是否是一個目錄 |
boolean | isFile() | 判斷 File 對象代表的文件是否是一個普通文件 |
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)行 |
String[] | list() | 返回 File 對象代表的目錄下的所有文件名 |
File[] | listFiles() | 返回 File 對象代表的目錄下的所有文件,以 File 對象表示 |
boolean | mkdir() | 創(chuàng)建 File 對象代表的目錄 |
boolean | mkdirs() | 創(chuàng)建 File 對象代表的目錄,如果必要,會創(chuàng)建中間目錄 |
boolean | renameTo(File dest) | 進(jìn)行文件改名,也可以視為我們平時的剪切、粘貼操作 |
boolean | canRead() | 判斷用戶是否對文件有可讀權(quán)限 |
boolean | canWrite() | 判斷用戶是否對文件有可寫權(quán)限 |
4.2方法的使用
1.得到文件的基本信息操作
package demo1;
import java.io.File;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
// 此處傳入的是絕對路徑,getPath得到的就是絕對路徑
File file = new File("E:/前端開發(fā)/實驗二/LX2/test.txt");
System.out.println("父目錄文件路徑: "+file.getParent());
System.out.println("文件名稱: "+file.getName());
System.out.println("文件路徑"+file.getPath());
System.out.println("文件的絕對路徑"+file.getAbsolutePath());
// 簡化了絕對路徑中的 . 和 ..
System.out.println("簡化過后的絕對路徑"+file.getCanonicalFile());
}
}打印結(jié)果:

2.顯示目錄下的文件操作
import java.io.File;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
File file = new File("E:/");
//list 只是列出當(dāng)前目錄的子元素,無法列出子目錄中的具體內(nèi)容
String[] list = file.list();
System.out.println(Arrays.toString(list));
System.out.println("================");
// File 對象代表的目錄下的所有文件,以 File 對象表示
File[] list2 = file.listFiles();
System.out.println(Arrays.toString(list2));
}
}打印結(jié)果:

3.創(chuàng)建目錄
當(dāng)前文件夾下為空,我們可以通過mkdir()創(chuàng)建目錄

public class Test {
public static void main(String[] args) {
File file = new File("E:/新建文件夾/text");
System.out.println(file.mkdir());
}
}
打印結(jié)果:

可以發(fā)現(xiàn)剛剛的文件夾下新建了一個名為text的目錄

4.總結(jié)
1.文件是存儲在硬盤上的。
2.目錄也是文件,操作系統(tǒng)通過樹形結(jié)構(gòu)組織目錄和文件的
3.通過路徑定位到具體的文件
4.文件分為:文本文件和二進(jìn)制文件
五、文件內(nèi)容操作
JAVA中針對文件內(nèi)容的操作,主要是通過一組流來實現(xiàn)的。
計算機(jī)中的流和水流非常相似:把數(shù)據(jù)看作連續(xù)不斷的字節(jié)序列,就像水管里流動的水。
水流的特點(diǎn):你可以用一桶接滿(一次取100升),也可以用兩個50升的桶分兩次接,或者用10個10升的桶……總之,只要最終總量是100升,取水方式可以任意拆分。
文件流同理:計算機(jī)把文件內(nèi)容視為一段連續(xù)字節(jié)流(byte stream)。讀取時,你可以一次 read(100) 全讀完,也可以循環(huán)10次、每次 read(10),甚至一次讀1字節(jié)、讀100次。只要每次讀的大小之和等于100,并且按順序讀取,都能正確拿到全部數(shù)據(jù)。
因此,計算機(jī)中針對讀寫文件,也是使用流(Stream)。
5.1流的分類
流有幾十種,可以分為兩個類別:
- 1.字節(jié)流:
讀寫文件以字節(jié)為單位,是針對二進(jìn)制文件使用的
InputStream 輸入 從文件讀數(shù)據(jù)
OutputStream 輸出 往文件寫數(shù)據(jù)
- 2.字符流:
讀寫文件以字符為單位,是針對文本文件使用的
Reader 輸入
Writer 輸出
輸入輸出是什么意思?
看數(shù)據(jù)的流向,從硬盤到CPU (輸入),從CPU到硬盤(輸出)
5.2 InputStream概述
1.方法
| 修飾符及返回值類型 | 方法簽名 | 說明 |
|---|---|---|
| int | read() | 讀取一個字節(jié)的數(shù)據(jù),返回 -1 代表已經(jīng)完全讀完了 |
| int | read(byte[] b) | 最多讀取 b.length 字節(jié)的數(shù)據(jù)到 b 中,返回實際讀到的數(shù)據(jù);-1 代表已經(jīng)讀完了 |
| int | read(byte[] b, int off, int len) | 最多讀取 len - off 字節(jié)的數(shù)據(jù)到 b 中,放在從 off 開始,返回實際讀到的數(shù)據(jù);-1 代表已經(jīng)讀完了 |
| void | close() | 關(guān)閉字節(jié)流 |

2.使用
三個步驟:
1.打開文件
2. 讀
3. 關(guān)閉
先創(chuàng)建一個名字為:text.txt的文件,內(nèi)容為hello

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException {
// InputStream是抽象類,不能直接new
// 創(chuàng)建對象成功就相當(dāng)于去打開文件
// try with resources 只要出現(xiàn)try代碼塊就會自動調(diào)用close
try(InputStream inputStream = new FileInputStream("./text.txt")){
while (true){
int i = inputStream.read();
if(i ==-1){
break;
}
System.out.println(i);
}
}
}
}
打印結(jié)果:hello這幾個字母對應(yīng)的ASCII表中的值

把text.txt中的文本內(nèi)容改成:你好

如果文件中包含 非 ASCII 字符(如中文 “你”、“好”、表情符號等),這些字符在 UTF-8 編碼下通常占多字節(jié)
一次讀一個字節(jié):
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException {
// InputStream是抽象類,不能直接new
// 創(chuàng)建對象成功就相當(dāng)于去打開文件
// try with resources 只要出現(xiàn)try代碼塊就會自動調(diào)用close
try(InputStream inputStream = new FileInputStream("./text.txt")){
while (true){
// 一次讀一個字節(jié)
int i = inputStream.read();
if(i ==-1){
break;
}
// 這里打印十六進(jìn)制 一個十六進(jìn)制數(shù)字是4個比特位,兩個十六進(jìn)制數(shù)字就是1一個字節(jié),所以選擇用十六進(jìn)制來進(jìn)行打印核對
System.out.printf("%x\n",i);
}
}
}
}
打印結(jié)果:

發(fā)現(xiàn)和上面的你好的UTF-8的碼表對應(yīng)上了。
一次讀多個字節(jié)
public class Test {
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("./text.txt")) {
//一次讀多個字節(jié) 數(shù)組的長度自行定義
byte[] data = new byte[3];
// 此處的讀操作盡可能讓數(shù)組填滿,
// 填不滿的話,能填幾個是幾個
while (true){
// 此處的n是實際讀到的字節(jié)數(shù)
int n = inputStream.read(data);
if(n == -1){
// 讀完了
break;
}
for(int i = 0; i<n;i++){
System.out.printf("%x\n",data[i]);
}
System.out.println("===========");
}
}
}
}
打印結(jié)果:一次讀三個字節(jié)

5.3 OutputStream概述
1.方法
| 修飾符及返回值類型 | 方法簽名 | 說明 |
|---|---|---|
| void | write(int b) | 寫入一個字節(jié)的數(shù)據(jù) |
| void | write(byte[] b) | 將 b 這個字節(jié)數(shù)組中的數(shù)據(jù)全部寫入輸出流中 |
| void | write(byte[] b, int off, int len) | 將 b 這個字節(jié)數(shù)組中從 off 開始的數(shù)據(jù)寫入輸出流中,一共寫 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è)備中。 |

這里的參數(shù)是int,主要是因為希望參數(shù)的取值范圍為:0~255,因為JAVA中沒有unsiged類型。
2.使用
示例:在output.txt文本文件中寫入abc
首先這里面沒有output.txt文本文件,等下我們可以觀察是否新建了一個output.txt文本文件并寫入abc

通過代碼來實現(xiàn)
import java.io.*;
public class Test {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("output.txt")){
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
} catch (IOException e) {
e.printStackTrace();
}
}
}
運(yùn)行結(jié)果:新建了一個output.txt文本文件并寫入了abc

對于OutputStream來說,如果文件不存在,會嘗試創(chuàng)建文件并寫入
OutputStream是會清處上一次的內(nèi)容,打開文件的一瞬間,就被清除了
示例:把剛剛的output.txt中的acb改為大寫的ABC
import java.io.*;
public class Test {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("output.txt")){
byte[] bytes = {65,66,67};
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
運(yùn)行結(jié)果

5.4Reader的使用

示例:
把text.txt文件中的abc讀出來
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Test {
public static void main(String[] args) {
try(Reader reader = new FileReader("text.txt")){
while (true){
int n = reader.read();
if(n == -1){
break;
}
System.out.println((char ) n);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印結(jié)果

5.5Writer的使用
將writer.txt中寫入hello world
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Test {
public static void main(String[] args) {
try(Writer writer = new FileWriter("./writer.txt")){
writer.write("hello world");
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印結(jié)果

在原來的hello world 的基礎(chǔ)上再追加寫hello world
public static void main(String[] args) {
//追加再寫一次hello world
try(Writer writer = new FileWriter("./writer.txt",true)){
writer.write("hello world ");
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印結(jié)果

以上就是Java文件操作與IO流詳解(File類+字節(jié)流+字符流)的詳細(xì)內(nèi)容,更多關(guān)于Java文件操作與IO流的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
List調(diào)用toString()方法后,去除兩頭的中括號實例
下面小編就為大家?guī)硪黄狶ist調(diào)用toString()方法后,去除兩頭的中括號實例。希望對大家有所幫助。一起跟隨小編過來看看吧2017-03-03
springboot多節(jié)點(diǎn)應(yīng)用里的雪花算法唯一性詳解
雪花算法在單節(jié)點(diǎn)下唯一,但在多副本Kubernetes環(huán)境中可能重復(fù),通過修改Pod名稱生成workId,解決了這個問題,同時避免了第三方組件和網(wǎng)絡(luò)請求,本文給大家介紹springboot多節(jié)點(diǎn)應(yīng)用里的雪花算法唯一性,感興趣的朋友一起看看吧2024-12-12
簡單操作實現(xiàn)Java jsp servlet文件上傳過程解析
這篇文章主要介紹了簡單操作實現(xiàn)Java jsp servlet文件上傳過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10
Spring security認(rèn)證兩類用戶代碼實例
這篇文章主要介紹了Spring security認(rèn)證兩類用戶代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
實現(xiàn)quartz定時器及quartz定時器原理介紹
Quartz是一個大名鼎鼎的Java版開源定時調(diào)度器,功能強(qiáng)悍,使用方便,下面我們看看如何使用它2013-12-12

