一文帶你搞懂Java中的數(shù)據(jù)流處理
數(shù)據(jù)流轉(zhuǎn)
在前端的javascrit中,我們幾乎是沒(méi)有能力對(duì)計(jì)算機(jī)上的某個(gè)文件進(jìn)行讀寫操作的,畢竟js只是一個(gè)網(wǎng)頁(yè)腳本。但是,nodejs是可以實(shí)現(xiàn)文件讀寫操作的。
在java中,對(duì)數(shù)據(jù)進(jìn)行讀寫操作非常容易!下圖展示了Java中數(shù)據(jù)流轉(zhuǎn)的大致過(guò)程:
數(shù)據(jù)從數(shù)據(jù)源通過(guò)管道(stream)流轉(zhuǎn)之?dāng)?shù)據(jù)目的地,管道的入口我們稱之為input,出口稱之為out,因此,數(shù)據(jù)流轉(zhuǎn)操作也稱之為IO操作。java中就封裝了IO類幫助我們操作文件。

文件流操作
要操作一個(gè)文件,我們必須先創(chuàng)建文件對(duì)象,使用文件路徑關(guān)聯(lián)系統(tǒng)文件。

如圖,我們Data文件夾有一個(gè)名 為testData的txt文件
想要獲得文件路徑,我們可以按照下圖的操作方式獲取

關(guān)聯(lián)好文件路徑,我們就可以對(duì)文件進(jìn)行一些操作了:
文件基礎(chǔ)操作
import java.io.File;
public class Data_IO {
public static void main(String[] args) {
// 文件流操作 基于 java.io
// 使用文件路徑關(guān)聯(lián)系統(tǒng)文件
String filePath = "D:\Code\JAVA\collection\src\Data\testData.txt";
// 創(chuàng)建文件對(duì)象
File file = new File(filePath);
// 文件對(duì)象的操作
// 判斷當(dāng)前文件對(duì)象是否文件(File對(duì)象也可能是文件夾)
System.out.println(file.isFile()); // true
// 判斷文件對(duì)象是否為文件夾
System.out.println(file.isDirectory()); // false
// 判斷文件是否關(guān)聯(lián)成功
System.out.println(file.exists()); // true
// 獲取文件名稱
System.out.println(file.getName()); // testData.txt
// 獲取文件長(zhǎng)度
System.out.println(file.lastModified()); // 1698977593862
// 獲取文件的絕對(duì)路徑
System.out.println(file.getAbsolutePath()); // D:\Code\JAVA\collection\src\Data\testData.txt
}
}
文件夾基礎(chǔ)操作
文件夾的一些基礎(chǔ)方法和文件是一致的。但有幾個(gè)方法是文件夾操作獨(dú)有的,如
獲取文件夾內(nèi)的數(shù)據(jù)列表

獲取文件夾中的文件對(duì)象
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1 ); // testData.txt
}
文件復(fù)制
在java中,實(shí)現(xiàn)文件復(fù)制是一個(gè)稍微復(fù)雜的過(guò)程?,F(xiàn)在,我們通過(guò)一個(gè)示例來(lái)演示下代碼。我們需要在Data文件夾下創(chuàng)建一個(gè)testData的副本文件testData_copy.txt

java中,對(duì)象復(fù)制的流程大致如下模型

首先,我們需要數(shù)據(jù)源對(duì)象和數(shù)據(jù)目的對(duì)象:
import java.io.*;
public class IO_Copy {
public static void main(String[] args) {
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
}
}
數(shù)據(jù)目的對(duì)象的路徑并不存在,是我們自己定義的要生成的文件路徑。
然后,我們要?jiǎng)?chuàng)建文件輸入管道1和文件輸出管道2:
import java.io.*;
public class IO_Copy {
public static void main(String[] args) {
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
// 文件輸入流(管道對(duì)象)
FileInputStream in = null;
// 文件輸出流(管道對(duì)象)
FileOutputStream out = null;
}
}
接下來(lái),我們就要打開閥門1和閥門2進(jìn)行數(shù)據(jù)流轉(zhuǎn)了
in = new FileInputStream(srcFile); out = new FileOutputStream(destFile); // 打開閥門,流轉(zhuǎn)數(shù)據(jù)(輸入端) int data = in.read(); // 打開閥門,流轉(zhuǎn)數(shù)據(jù)(輸出端) out.write(data);
數(shù)據(jù)流轉(zhuǎn)完畢,我們需要關(guān)閉管道
in.close(); out.close();
當(dāng)然,數(shù)據(jù)操作過(guò)程中,存在很多異常情況,比如找不到數(shù)據(jù)源文件等等,所以實(shí)際代碼中,我們需要進(jìn)行異常處理。比較完成的代碼如下:
import java.io.*;
public class IO_Copy {
public static void main(String[] args) {
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
// 文件輸入流(管道對(duì)象)
FileInputStream in = null;
// 文件輸出流(管道對(duì)象)
FileOutputStream out = null;
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFile);
// 打開閥門1,流轉(zhuǎn)數(shù)據(jù)(輸入端)
int data = in.read();
// 打開閥門2,流轉(zhuǎn)數(shù)據(jù)(輸出端)
out.write(data);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(in != null){
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
我們來(lái)運(yùn)行看看

可以看到,文件復(fù)制的確完成了,但是為什么復(fù)制出來(lái)的文件只有一個(gè)H字符???
這其實(shí)和java的文件復(fù)制原理有關(guān),文件流復(fù)制時(shí),是這個(gè)過(guò)程:
復(fù)制時(shí),閥門1打開,H字符進(jìn)入管道1:

當(dāng)H字符進(jìn)入管道2時(shí),閥門1關(guān)閉,閥門2打開

當(dāng)H字符進(jìn)入數(shù)據(jù)目的地后,閥門2也隨之關(guān)閉,復(fù)制完成

在上述代碼中,我們的閥門1和閥門2只開啟過(guò)一次,自然只能復(fù)制一個(gè)H字符
in = new FileInputStream(srcFile); out = new FileOutputStream(destFile); // 打開閥門1,流轉(zhuǎn)數(shù)據(jù)(輸入端) int data = in.read(); // 打開閥門2,流轉(zhuǎn)數(shù)據(jù)(輸出端) out.write(data);
所以很簡(jiǎn)單,我們只需要循環(huán)執(zhí)行上述代碼即可!那該執(zhí)行幾次呢?我們看下面代碼:

我們將閥門多開啟了一次,導(dǎo)致副本文件多了一個(gè)亂碼字符,通過(guò)打印結(jié)果可見(jiàn),當(dāng)data值為-1前,終止這個(gè)循環(huán)即可!改寫代碼:
import java.io.*;
public class IO_Copy {
public static void main(String[] args) {
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
// 文件輸入流(管道對(duì)象)
FileInputStream in = null;
// 文件輸出流(管道對(duì)象)
FileOutputStream out = null;
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFile);
// 打開閥門,流轉(zhuǎn)數(shù)據(jù)(輸入端)
int data = in.read();
out.write(data);
// 打開閥門,流轉(zhuǎn)數(shù)據(jù)(輸出端)
while ((data = in.read()) != -1){
out.write(data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(in != null){
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
緩沖流
上述的文件復(fù)制效率很低,每復(fù)制一個(gè)字符,都要開啟關(guān)閉閥門一次,因此,java也提供了緩沖區(qū)的優(yōu)化方式。
它的概念非常容易,就是在文件傳輸?shù)墓艿乐?,增加了一個(gè)緩沖管道

其復(fù)制流程大致如下:
閥門1打開,所有內(nèi)容進(jìn)入管道1

閥門1關(guān)閉,所有內(nèi)容進(jìn)入緩沖區(qū)

緩沖區(qū)內(nèi)容進(jìn)入管道2,閥門2打開

管道2內(nèi)容進(jìn)入數(shù)據(jù)目的地,復(fù)制完成,閥門2關(guān)閉。

完整代碼如下:
import java.io.*;
public class IO_Copy {
public static void main(String[] args) {
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
// 文件輸入流(管道對(duì)象)
FileInputStream in = null;
// 文件輸出流(管道對(duì)象)
FileOutputStream out = null;
// 緩沖輸入流
BufferedInputStream bufferIn = null;
BufferedOutputStream bufferOut = null;
// 創(chuàng)建一個(gè)大小為1024字節(jié)的緩存區(qū)cache。這將用于存儲(chǔ)從源文件讀取的數(shù)據(jù),然后再寫入目標(biāo)文件。
byte[] cache = new byte[1024];
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFile);
// 緩沖輸入流
bufferIn = new BufferedInputStream(in);
// 緩沖輸出流
bufferOut = new BufferedOutputStream(out);
// 數(shù)據(jù)流轉(zhuǎn)
int data;
// 當(dāng)讀取到文件末尾(即data為-1)時(shí),循環(huán)結(jié)束。
while ((data = bufferIn.read(cache)) != -1){
bufferOut.write(cache,0,data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(bufferIn != null){
try {
bufferIn.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(bufferOut != null){
try {
bufferOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
字符流操作
文件流的操作是基于文件的字節(jié)實(shí)現(xiàn)的。字符流的操作提供了另一種通過(guò)一行字符的形式操作數(shù)據(jù)。

再文件復(fù)制時(shí),它會(huì)將一整行的字符一次性復(fù)制過(guò)去。
它的語(yǔ)法流程如下
首先,定義兩個(gè)File對(duì)象,srcFile和destFile。這兩個(gè)對(duì)象分別代表了源文件(我們要從中讀取數(shù)據(jù)的文件)和目標(biāo)文件(我們要寫入數(shù)據(jù)的文件)。
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
然后,創(chuàng)建了兩個(gè)流對(duì)象,reader和writer。這兩個(gè)對(duì)象分別用于從源文件讀取數(shù)據(jù)和向目標(biāo)文件寫入數(shù)據(jù)。
BufferedReader reader = null; PrintWriter writer = null;
接著,使用reader讀取源文件的內(nèi)容,而writer會(huì)向目標(biāo)文件寫入內(nèi)容。
try {
reader = new BufferedReader(new FileReader(srcFile));
writer = new PrintWriter(destFile);
...
} catch (IOException e) {
throw new RuntimeException(e);
}
在try塊中,讀取源文件的內(nèi)容。每次讀取一行,直到文件結(jié)束(也就是沒(méi)有更多的行可以讀?。C孔x取一行,我們都會(huì)打印這一行(在控制臺(tái)輸出),并且寫入到目標(biāo)文件。
while ((line = reader.readLine()) != null){
System.out.println(line); // 打印到控制臺(tái)
writer.println(line); // 寫入到目標(biāo)文件
}
在讀取和寫入操作結(jié)束后,我們調(diào)用writer.flush()方法,確保所有待寫入的數(shù)據(jù)都被立即寫入到目標(biāo)文件。
writer.flush();
完整代碼如下:
import java.io.*;
public class IO_Copy {
public static void main(String[] args) {
// 數(shù)據(jù)源對(duì)象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 數(shù)據(jù)目的地對(duì)象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
// 字符輸入流(管道對(duì)象)
BufferedReader reader = null;
// 字符輸出流(管道對(duì)象)
PrintWriter writer = null;
try {
reader = new BufferedReader(new FileReader(srcFile));
writer = new PrintWriter(destFile);
// 讀取文件的一行數(shù)據(jù)(字符串)
String line = null;
while ((line = reader.readLine()) != null){
System.out.println(line); // Hello
writer.println(line);
}
// 刷寫數(shù)據(jù)
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(reader != null){
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
以上就是一文帶你搞懂Java中的數(shù)據(jù)流處理的詳細(xì)內(nèi)容,更多關(guān)于Java數(shù)據(jù)流處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實(shí)現(xiàn)會(huì)反彈的小球示例
這篇文章主要介紹了java實(shí)現(xiàn)會(huì)反彈的小球示例,需要的朋友可以參考下2014-04-04
Hibernate validator使用以及自定義校驗(yàn)器注解
這篇文章主要介紹了Hibernate validator使用以及自定義校驗(yàn)器注解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
SpringBoot中實(shí)現(xiàn)訂單30分鐘自動(dòng)取消的三種方案分享
在電商和其他涉及到在線支付的應(yīng)用中,通常需要實(shí)現(xiàn)一個(gè)功能:如果用戶在生成訂單后的一定時(shí)間內(nèi)未完成支付,系統(tǒng)將自動(dòng)取消該訂單,本文將詳細(xì)介紹基于Spring Boot框架實(shí)現(xiàn)訂單30分鐘內(nèi)未支付自動(dòng)取消的幾種方案,并提供實(shí)例代碼,需要的朋友可以參考下2023-10-10
Java中面向?qū)ο蟮闹R(shí)點(diǎn)總結(jié)
Java是一門面向?qū)ο蟮恼Z(yǔ)言。對(duì)象是Java程序中的基本實(shí)體。除了對(duì)象之外Java程序同樣處理基本數(shù)據(jù)。下面這篇文章主要給大家總結(jié)了關(guān)于Java中面向?qū)ο蟮闹R(shí)點(diǎn),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02
通過(guò)AOP環(huán)繞通知如何實(shí)現(xiàn)事務(wù)控制
這篇文章主要介紹了通過(guò)AOP環(huán)繞通知如何實(shí)現(xiàn)事務(wù)控制的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署步驟詳解
這篇文章主要介紹了Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
JAVA SPI特性及簡(jiǎn)單應(yīng)用代碼實(shí)例
這篇文章主要介紹了JAVA SPI特性及簡(jiǎn)單應(yīng)用代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05

