自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

文件讀寫操作與常用技巧分享,你學(xué)會(huì)了嗎?

開發(fā) 前端
Java 中通常的 File 并不代表一個(gè)真實(shí)存在的文件對(duì)象,當(dāng)你通過指定一個(gè)路徑描時(shí),它就會(huì)返回一個(gè)代表這個(gè)路徑相關(guān)聯(lián)的一個(gè)虛擬對(duì)象,這個(gè)可能是一個(gè)真實(shí)存在的文件或者是一個(gè)包含多個(gè)文件的目錄。

一、摘要

在之前的文章中,我們了解到在 Java I/O 體系中,F(xiàn)ile 類是唯一代表磁盤文件本身的對(duì)象。

File 類定義了一些與平臺(tái)無關(guān)的方法來操作文件,包括檢查一個(gè)文件是否存在、創(chuàng)建、刪除文件、重命名文件、判斷文件的讀寫權(quán)限是否存在、設(shè)置和查詢文件的最近修改時(shí)間等等操作。

值得注意的地方是,Java 中通常的 File 并不代表一個(gè)真實(shí)存在的文件對(duì)象,當(dāng)你通過指定一個(gè)路徑描時(shí),它就會(huì)返回一個(gè)代表這個(gè)路徑相關(guān)聯(lián)的一個(gè)虛擬對(duì)象,這個(gè)可能是一個(gè)真實(shí)存在的文件或者是一個(gè)包含多個(gè)文件的目錄。

下面我們一起來看看 File 類有哪些操作方法,以及實(shí)際使用過程中如何避坑。

二、File 類介紹

大家 JDK 中源代碼,你會(huì)發(fā)現(xiàn) File 類沒有無參構(gòu)造方法,最常用的是使用下面的構(gòu)造方法來生成 File 對(duì)象。

以 windows 操作系統(tǒng)為例,操作文件的方式如下!

// 指定一個(gè)完整路徑,獲取文件對(duì)象
File file = new File("D:\\Files\\test.txt");
System.out.println(file1.getName());

// 指定一個(gè)父文件路徑和子文件名稱,獲取文件對(duì)象
File file = new File("D:\\Files", "test.txt");
System.out.println(file2.getName());

File 類中定義了很多關(guān)于 File 對(duì)象的一些操作方法,我們通過一段代碼一起來看看。

public static void main(String[] args) throws Exception {
    // 指定一個(gè)文件完整路徑,獲取文件對(duì)象
    File file = new File("D:\\Files\\test.txt");

    // 獲取文件父節(jié)點(diǎn)目錄對(duì)象
    File parentFile = file.getParentFile();

    // 判斷指定路徑的文件目錄是否存在
    if(parentFile.exists()){
        System.out.println("文件目錄存在");
    } else {
        // 創(chuàng)建文件夾,可以自動(dòng)創(chuàng)建多級(jí)文件夾
        parentFile.mkdirs();
        System.out.println("文件目錄不存在,創(chuàng)建一個(gè)文件目錄");
    }

    // 判斷指定父節(jié)點(diǎn)路徑的是否是一個(gè)目錄
    if(parentFile.isDirectory()){
        System.out.println("父節(jié)點(diǎn)路徑是一個(gè)目錄");
    }

    // 判斷指定路徑的文件是否存在
    if(file.exists()){
        System.out.println("文件存在");
    } else {
        // 創(chuàng)建文件
        file.createNewFile();
        System.out.println("文件不存在,創(chuàng)建一個(gè)文件");
    }
    
    // 獲取目錄下的所有文件/文件夾(僅該層路徑下)
    File[] files = parentFile.listFiles();
    System.out.print("路徑下有文件:");
    for (File f : files) {
        System.out.print(f + ";");
    }
    System.out.println();

    // 獲取文件名、文件夾名
    System.out.println("files[0]的文件名:" + files[0].getName());
    // 獲取文件、文件夾路徑
    System.out.println("files[0]的文件路徑:" + files[0].getPath());
    // 獲取文件、文件夾絕對(duì)路徑
    System.out.println("files[0]的絕對(duì)路徑:" + files[0].getAbsolutePath());
    // 獲取文件父目錄路徑
    System.out.println("files[0]的父文件夾名:" + files[0].getParent());
    // 判斷文件、文件夾是否存在
    System.out.println(files[0].exists() ? "files[0]的存在" : "files[0]的不存在");
    // 判斷文件是否可寫
    System.out.println(files[0].canWrite() ? "files[0]的可寫" : "files[0]的不可寫");
    // 判斷文件是否可讀
    System.out.println(files[0].canRead() ? "files[0]的可讀" : "files[0]的不可讀");
    // 判斷文件是否可執(zhí)行
    System.out.println(files[0].canExecute() ? "file[0]可執(zhí)行" : "file[0]不可執(zhí)行");
    // 判斷文件、文件夾是不是目錄
    System.out.println(files[0].isDirectory() ? "files[0]的是目錄" : "files[0]的不是目錄");
    // 判斷拿文件、文件夾是不是標(biāo)準(zhǔn)文件
    System.out.println(files[0].isFile() ? "files[0]的是文件" : "files[0]的不是文件");
    // 判斷路徑名是不是絕對(duì)路徑
    System.out.println(files[0].isAbsolute() ? "files[0]的路徑名是絕對(duì)路徑" : "files[0]的路徑名不是絕對(duì)路徑");
    // 獲取文件、文件夾上一次修改時(shí)間
    System.out.println("files[0]的最后修改時(shí)間:" + files[0].lastModified());
    // 獲取文件的字節(jié)數(shù),如果是一個(gè)文件夾則這個(gè)值為0
    System.out.println("files[0]的大?。? + files[0].length() + " Bytes");
    // 獲取文件路徑URI后的路徑名
    System.out.println("files[0]的路徑轉(zhuǎn)換為URI:" + files[0].toURI());

    // 下面的代碼邏輯,假設(shè)目錄下有3個(gè)以上文件

    // 對(duì)文件重命名
    File newfile = new File(file.getParentFile(), "22.txt");  //新的文件名稱
    files[0].renameTo(newfile);

    // 刪除指定的文件、文件夾
    files[1].delete();

    // 當(dāng)虛擬機(jī)終止時(shí)刪除指定的文件、文件夾
    files[2].deleteOnExit();
}

輸出結(jié)果如下:

文件目錄存在
父節(jié)點(diǎn)路徑是一個(gè)目錄
文件存在
路徑下有文件:D:\Files\1.txt;D:\Files\2.txt;D:\Files\3.txt;
files[0]1.txt
files[0]的文件路徑:D:\Files\1.txt
files[0]的絕對(duì)路徑:D:\Files\1.txt
files[0]的父文件夾名:D:\Files
files[0]的存在
files[0]的可寫
files[0]的可讀
file[0]不可執(zhí)行
files[0]的不是目錄
files[0]的是文件
files[0]的路徑名是絕對(duì)路徑
files[0]的最后修改時(shí)間:1686814709000
files[0]的大?。? Bytes
files[0]的路徑轉(zhuǎn)換為URI:file:/D:/Files/1.txt

示例代碼中,基本比較全面地演示了 File 的一些基本用法,比如文件或者文件夾的新增、重命名、刪除,以及獲取文件或者文件夾相關(guān)信息等操作。

其中有兩點(diǎn)地方,值得注意:

  • 第一個(gè)就是分隔符的問題。不同的操作系統(tǒng),路徑分隔符是不一樣的,這個(gè)可以通過File.separator解決,具體實(shí)現(xiàn)看下面
  • 第二個(gè)就是刪除的如果是一個(gè)文件夾的話,文件夾下還有文件/文件夾,是無法刪除成功的

關(guān)于不同操作系統(tǒng)下的路徑符號(hào)問題解決辦法?。╳indows->“\”;Linux->“/”)

在實(shí)際的編程過程中,我們不可能為了區(qū)分操作系統(tǒng),然后又單獨(dú)寫一份文件路徑。

可以通過File.separator來實(shí)現(xiàn)跨平臺(tái)的編程邏輯,F(xiàn)ile.separator會(huì)根據(jù)不同的操作系統(tǒng)取不同操作系統(tǒng)下的分隔符。

以上面的示范代碼為例,我們可以對(duì)寫法進(jìn)行如下改造!

// windows 系統(tǒng)下的文件絕對(duì)路徑定義方式
String path = "d:"+File.separator +"Files"+File.separator+"text.txt";
File file = new File(path);

文件的路徑結(jié)果會(huì)與預(yù)期一致!

三、文件的讀寫操作

對(duì)文件的讀寫,可以通過字節(jié)流或者字符流接口來完成,但不管哪種方式,大致分以下幾個(gè)步驟完成。

  • 第一步:獲取一個(gè)文件 file 對(duì)象
  • 第二步:通過 file 對(duì)象,獲取一個(gè)字節(jié)流或者字符流接口的對(duì)象,進(jìn)行讀寫操作
  • 第三步:關(guān)閉文件流

具體的代碼實(shí)踐如下!

3.1、通過字節(jié)流接口寫入

字節(jié)流接口的文件寫入,可以通過OutputStream下的子類FileOutputStream來實(shí)現(xiàn)文件的數(shù)據(jù)寫入操作。

具體實(shí)例如下:

// 創(chuàng)建一個(gè) readWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(!file.exists()){
    file.createNewFile();
}

// 向文件中寫入數(shù)據(jù)(這種方式會(huì)覆蓋原始數(shù)據(jù))
OutputStream outputStream = new FileOutputStream(file);
String str = "我們一起學(xué)習(xí)Java";
outputStream.write(str.getBytes(StandardCharsets.UTF_8));
outputStream.close();

上面的操作方式會(huì)覆蓋原始數(shù)據(jù),如果想在已有的文件里面,進(jìn)行追加寫入數(shù)據(jù),可以如下方式實(shí)現(xiàn)。

// 追加數(shù)據(jù)寫入(這種方式不會(huì)覆蓋原始數(shù)據(jù))
OutputStream appendOutputStream = new FileOutputStream(file, true);
String str = "-----這是追加的內(nèi)容------";
appendOutputStream.write(str.getBytes(StandardCharsets.UTF_8));
appendOutputStream.close();

3.2、通過字節(jié)流接口讀取

字節(jié)流方式的文件讀取,可以通過InputStream下的子類FileInputStream來實(shí)現(xiàn)文件的數(shù)據(jù)讀取操作。

具體實(shí)例如下:

// 獲取 readWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(file.exists()){
    // 獲取文件流
    InputStream input = new FileInputStream(file);

    // 臨時(shí)區(qū)
    byte[] buffer = new byte[1024];

    // 分次讀取數(shù)據(jù),每次最多讀取1024個(gè)字節(jié),將數(shù)據(jù)讀取到臨時(shí)區(qū)之中,同時(shí)返回讀取的字節(jié)個(gè)數(shù),如果遇到文件末尾,會(huì)返回-1
    int len;
    while ((len = input.read(buffer)) > -1) {
        // 字節(jié)轉(zhuǎn)為字符串
        String msg = new String(buffer, 0, len, StandardCharsets.UTF_8);
        System.out.println(msg);
    }

    // 數(shù)據(jù)讀取完畢之后,關(guān)閉輸入流
    input.close();
}

3.3、通過字符流接口寫入

在之前的文章中,我們了解到為了簡(jiǎn)化字符的數(shù)據(jù)傳輸操作,JDK 提供了 Writer 與 Reader 字符流接口。

字符流方式的文件寫入,可以通過Writer下的子類FileWriter來實(shí)現(xiàn)文件的數(shù)據(jù)寫入操作。

具體實(shí)例如下:

// 創(chuàng)建一個(gè) newReadWriteDemo.txt 文件
File file = new File("newReadWriteDemo.txt");
if(!file.exists()){
    file.createNewFile();
}
// 實(shí)例化Writer類對(duì)象
Writer out = new FileWriter(file) ;
// 輸出字符串
out.write("Hello");
// 輸出換行
out.write("\n");
// 追加信息,append 方法底層本質(zhì)調(diào)用的是 write 方法
out.append("我們一起來學(xué)習(xí)Java");

// 關(guān)閉輸出流
out.close();

3.4、通過字符流接口讀取

字符流方式的文件讀取,可以通過Reader下的子類FileReader來實(shí)現(xiàn)文件的數(shù)據(jù)讀取操作。

具體實(shí)例如下:

// 創(chuàng)建一個(gè) newReadWriteDemo.txt 文件
File file = new File("newReadWriteDemo.txt");
if(file.exists()){
    // 實(shí)例化輸入流
    Reader reader = new FileReader(file);
    // 臨時(shí)區(qū)
    char[] buffer = new char[1024];

    // 分次讀取數(shù)據(jù),每次最多讀取1024個(gè)字符,將數(shù)據(jù)讀取到臨時(shí)區(qū)之中,同時(shí)返回讀取的字節(jié)個(gè)數(shù),如果遇到文件末尾,會(huì)返回-1
    int len;
    while ((len = reader.read(buffer)) > -1) {
        // 字符轉(zhuǎn)為字符串
        String msg = new String(buffer, 0, len);
        System.out.println(msg);
    }

    // 關(guān)閉輸入流
    reader.close();
}

3.5、文件拷貝

在實(shí)際的軟件開發(fā)過程中,避免不了文件拷貝。通過以上的接口方法,我們可以很容易的寫出一個(gè)文件復(fù)制的方法。

比如以字節(jié)流操作為例,具體實(shí)例如下:

// 1. 創(chuàng)建一個(gè)字節(jié)數(shù)組作為數(shù)據(jù)讀取的臨時(shí)區(qū)
byte[] buffer = new byte[1024];
// 2. 創(chuàng)建一個(gè) FileInputStream 對(duì)象用于讀取文件
InputStream input = new FileInputStream(new File("input.txt"));
// 3. 創(chuàng)建一個(gè) FileOutputStream 對(duì)象用于寫入文件
OutputStream output = new FileOutputStream(new File("output.txt"));
// 4. 循環(huán)讀取文件內(nèi)容到臨時(shí)區(qū),并將臨時(shí)區(qū)中的數(shù)據(jù)寫入到輸出文件中
int length;
while ((length = input.read(buffer)) != -1) {
    output.write(buffer, 0, length);
}
// 5. 關(guān)閉輸入流
input.close();
// 6. 關(guān)閉輸出流
output.close();

除此之外,JDK 也支持采用緩存流讀寫技術(shù)來實(shí)現(xiàn)數(shù)據(jù)的高效讀寫。

之所為高效,是因?yàn)樽止?jié)緩沖流內(nèi)部維護(hù)了一個(gè)緩沖區(qū),讀寫時(shí)先將數(shù)據(jù)存入緩沖區(qū)中,當(dāng)緩沖區(qū)滿時(shí)再將數(shù)據(jù)一次性讀取出來或者寫入進(jìn)去,這樣可以減少與磁盤實(shí)際的 I/O 操作次數(shù),可以顯著提升讀寫操作的效率。

比如以字節(jié)流緩沖流為例,包裝類分別是:BufferedInputStream(字節(jié)緩存輸入流) 和 BufferedOutputStream(字符緩存輸入流)。

采用緩沖流拷貝文件,具體實(shí)例如下:

// 1. 創(chuàng)建一個(gè)字節(jié)數(shù)組作為數(shù)據(jù)讀取的臨時(shí)區(qū)
byte[] buffer = new byte[1024];
// 2. 創(chuàng)建一個(gè) BufferedInputStream 緩存輸入流對(duì)象用于讀取文件
InputStream bis = new BufferedInputStream(new FileInputStream(new File("input.txt")));
// 3. 創(chuàng)建一個(gè) BufferedOutputStream 緩存輸出流對(duì)象用于寫入文件
OutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("output.txt")));

// 4. 循環(huán)讀取文件內(nèi)容到臨時(shí)區(qū),并將緩沖區(qū)中的數(shù)據(jù)寫入到輸出文件中
int length;
while ((length = bis.read(buffer)) != -1) {
    bos.write(buffer, 0, length);
}
// 5. 關(guān)閉輸入流
bis.close();
// 6. 關(guān)閉輸出流
bos.close();

在大文件的拷貝中,使用緩存流比不使用緩存流技術(shù)至少快 10 倍,耗時(shí)是很明顯的,大家可以親自試一下。

四、字節(jié)流與字符流的互轉(zhuǎn)

在之前的文章中,我們了解到字節(jié)流與字符流,兩者其實(shí)是可以互轉(zhuǎn)的。

其中 InputStreamReader 和 OutputStreamWriter 就是轉(zhuǎn)化橋梁。

4.1、字節(jié)流轉(zhuǎn)字符流的操作

字節(jié)流轉(zhuǎn)字符流的操作,主要體現(xiàn)在數(shù)據(jù)的讀取階段,轉(zhuǎn)化過程如下圖所示:

圖片

以上文中的字節(jié)流接口讀取文件為例,如果我們想要轉(zhuǎn)換字符流接口來讀取數(shù)據(jù),具體的操作方式如下:

// 獲取 readWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(file.exists()){
    // 獲取字節(jié)輸入流
    InputStream inputStream = new FileInputStream(file);
    // 轉(zhuǎn)字符流輸入流,指定 UTF_8 編碼規(guī)則,讀取數(shù)據(jù)
    Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);

    // 緩沖區(qū)
    char[] buffer = new char[1024];

    // 分次讀取數(shù)據(jù),每次最多讀取1024個(gè)字符,將數(shù)據(jù)讀取到緩沖區(qū)之中,同時(shí)返回讀取的字節(jié)個(gè)數(shù)
    int len;
    while ((len = reader.read(buffer)) > -1) {
        // 字符轉(zhuǎn)為字符串
        String msg = new String(buffer, 0, len);
        System.out.println(msg);
    }

    // 關(guān)閉輸入流
    reader.close();
    inputStream.close();
}

當(dāng)讀取數(shù)據(jù)的時(shí)候,先通過字節(jié)流讀取,再轉(zhuǎn)成字符流讀取。

字節(jié)流轉(zhuǎn)字符流,需要指定編碼規(guī)則,如果沒有指定,會(huì)取當(dāng)系統(tǒng)默認(rèn)的編碼規(guī)則。

4.2、字符流轉(zhuǎn)字節(jié)流的操作

字符流轉(zhuǎn)字節(jié)流的操作,主要體現(xiàn)在數(shù)據(jù)的寫入階段,轉(zhuǎn)化過程如下圖所示:

圖片圖片

以上文中的字節(jié)流接口寫入文件為例,如果我們想要轉(zhuǎn)換字符流接口來寫入數(shù)據(jù),具體的操作方式如下:

// 創(chuàng)建一個(gè) newReadWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(!file.exists()){
    file.createNewFile();
}

// 獲取字節(jié)輸出流
OutputStream outputStream = new FileOutputStream(file);
// 轉(zhuǎn)字符流輸出流,指定 UTF_8 編碼規(guī)則,寫入數(shù)據(jù)
Writer out = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
// 輸出字符串
out.write("Hello");
// 輸出換行
out.write("\n");
// 追加信息,append 方法底層本質(zhì)調(diào)用的是 write 方法
out.append("我們一起來學(xué)習(xí)Java");

// 關(guān)閉輸出流
out.close();
outputStream.close();

同樣的,當(dāng)寫入數(shù)據(jù)的時(shí)候,先通過字符流寫入,再轉(zhuǎn)成字節(jié)流輸出。

字符流轉(zhuǎn)字節(jié)流,也需要指定編碼規(guī)則,如果沒有指定,會(huì)取當(dāng)系統(tǒng)默認(rèn)的編碼規(guī)則。

五、小結(jié)

本文主要圍繞 Java 對(duì)磁盤文件的讀取和寫入數(shù)據(jù)的方式做了一次簡(jiǎn)單的總結(jié)。

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2023-12-07 07:03:09

2023-08-28 07:02:10

2025-01-09 07:58:42

C#API函數(shù)

2023-04-10 09:31:00

路由技術(shù)廠商

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機(jī)器學(xué)習(xí)模型

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺(tái)工具

2024-01-19 08:25:38

死鎖Java通信

2023-01-10 08:43:15

定義DDD架構(gòu)

2024-02-06 08:33:54

文件系統(tǒng)SSD

2023-05-18 09:01:11

MBRGPT分區(qū)

2023-06-08 07:34:19

HDFS小文件壓縮包

2024-02-27 08:39:19

RustJSON字符串

2023-08-22 10:25:19

CSS動(dòng)畫網(wǎng)頁(yè)

2022-07-13 08:16:49

RocketMQRPC日志

2023-01-31 08:02:18

2023-05-05 06:54:07

MySQL數(shù)據(jù)查詢

2023-08-26 21:34:28

Spring源碼自定義

2022-06-16 07:50:35

數(shù)據(jù)結(jié)構(gòu)鏈表
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)