一文搞懂java中的数据流处理

数据流转

在前端的javascrit中,我们几乎是没有能力对计算机上的某个文件进行读写操作的,毕竟js只是一个网页脚本。但是,nodejs是可以实现文件读写操作的。

在java中,对数据进行读写操作非常容易!下图展示了Java中数据流转的大致过程:

数据从数据源 通过管道 (stream)流转之数据目的地,管道的入口我们称之为input ,出口称之为out ,因此,数据流转操作也称之为IO操作。java中就封装了IO类帮助我们操作文件。

文件流操作

要操作一个文件,我们必须先创建文件对象,使用文件路径关联系统文件。

如图,我们Data文件夹有一个名 为testData的txt文件

想要获得文件路径,我们可以按照下图的操作方式获取

关联好文件路径,我们就可以对文件进行一些操作了:

文件基础操作

csharp 复制代码
import java.io.File;

public class Data_IO {
    public static void main(String[] args) {
        // 文件流操作 基于 java.io
        // 使用文件路径关联系统文件
        String filePath = "D:\Code\JAVA\collection\src\Data\testData.txt";

        //  创建文件对象
        File file = new File(filePath);
        
        // 文件对象的操作

        // 判断当前文件对象是否文件(File对象也可能是文件夹)
        System.out.println(file.isFile());            // true
        // 判断文件对象是否为文件夹
        System.out.println(file.isDirectory());       // false
        // 判断文件是否关联成功
        System.out.println(file.exists());            // true
        // 获取文件名称
        System.out.println(file.getName());           // testData.txt
        // 获取文件长度
        System.out.println(file.lastModified());      // 1698977593862
        // 获取文件的绝对路径
        System.out.println(file.getAbsolutePath());   // D:\Code\JAVA\collection\src\Data\testData.txt
    }
}

文件夹基础操作

文件夹的一些基础方法和文件是一致的。但有几个方法是文件夹操作独有的,如

  • 获取文件夹内的数据列表
  • 获取文件夹中的文件对象
ini 复制代码
File[] files = file.listFiles();
for (File file1 : files) {
    System.out.println(file1 );  // testData.txt
}

文件复制

在java中,实现文件复制是一个稍微复杂的过程。现在,我们通过一个示例来演示下代码。我们需要在Data文件夹下创建一个testData 的副本文件testData_copy.txt

java中,对象复制的流程大致如下模型

首先,我们需要数据源对象数据目的对象:

java 复制代码
import java.io.*;

public class IO_Copy {
    public static void main(String[] args) {
        // 数据源对象
        File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
        // 数据目的地对象
        File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
    }
}
  • 数据目的对象的路径并不存在,是我们自己定义的要生成的文件路径。

然后,我们要创建文件输入管道1文件输出管道2:

java 复制代码
import java.io.*;

public class IO_Copy {
    public static void main(String[] args) {
        // 数据源对象
        File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
        // 数据目的地对象
        File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");
        // 文件输入流(管道对象)
        FileInputStream in = null;
        // 文件输出流(管道对象)
        FileOutputStream out = null;
    }
}

接下来,我们就要打开阀门1阀门2进行数据流转了

ini 复制代码
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFile);
// 打开阀门,流转数据(输入端)
int data = in.read();
// 打开阀门,流转数据(输出端)
out.write(data);

数据流转完毕,我们需要关闭管道

go 复制代码
in.close();
out.close();

当然,数据操作过程中,存在很多异常情况,比如找不到数据源文件等等,所以实际代码中,我们需要进行异常处理。比较完成的代码如下:

java 复制代码
import java.io.*;

public class IO_Copy {
    public static void main(String[] args) {
        // 数据源对象
        File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
        // 数据目的地对象
        File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");

        // 文件输入流(管道对象)
        FileInputStream in = null;
        // 文件输出流(管道对象)
        FileOutputStream out = null;
        try {
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(destFile);
            // 打开阀门1,流转数据(输入端)
            int data = in.read();
            // 打开阀门2,流转数据(输出端)
            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);
                }
            }
        }
    }
}

我们来运行看看

可以看到,文件复制的确完成了,但是为什么复制出来的文件只有一个H字符???

这其实和java的文件复制原理有关,文件流复制时,是这个过程:

复制时,阀门1 打开,H字符 进入管道1:

H字符 进入管道2 时,阀门1 关闭,阀门2打开

H字符 进入数据目的地 后,阀门2也随之关闭,复制完成

在上述代码中,我们的阀门1阀门2 只开启过一次,自然只能复制一个H字符

ini 复制代码
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFile);
// 打开阀门1,流转数据(输入端)
int data = in.read();
// 打开阀门2,流转数据(输出端)
out.write(data);

所以很简单,我们只需要循环执行上述代码即可!那该执行几次呢?我们看下面代码:

我们将阀门多开启了一次,导致副本文件多了一个乱码字符,通过打印结果可见,当data值为-1前,终止这个循环即可!改写代码:

java 复制代码
import java.io.*;

public class IO_Copy {
    public static void main(String[] args) {
        // 数据源对象
        File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
        // 数据目的地对象
        File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");

        // 文件输入流(管道对象)
        FileInputStream in = null;
        // 文件输出流(管道对象)
        FileOutputStream out = null;
        try {
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(destFile);
            // 打开阀门,流转数据(输入端)
            int data = in.read();
            out.write(data);

            // 打开阀门,流转数据(输出端)
            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);
                }
            }
        }
    }
}

缓冲流

上述的文件复制效率很低,每复制一个字符,都要开启关闭阀门一次,因此,java也提供了缓冲区的优化方式。

它的概念非常容易,就是在文件传输的管道中,增加了一个缓冲管道

其复制流程大致如下:

阀门1 打开,所有内容进入管道1

阀门1 关闭,所有内容进入缓冲区

缓冲区 内容进入管道2阀门2 打开

管道2 内容进入数据目的地 ,复制完成,阀门2关闭。

完整代码如下:

java 复制代码
import java.io.*;

public class IO_Copy {
    public static void main(String[] args) {
        // 数据源对象
        File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
        // 数据目的地对象
        File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");

        // 文件输入流(管道对象)
        FileInputStream in = null;
        // 文件输出流(管道对象)
        FileOutputStream out = null;

        // 缓冲输入流
        BufferedInputStream bufferIn = null;
        BufferedOutputStream bufferOut = null;

        // 创建一个大小为1024字节的缓存区cache。这将用于存储从源文件读取的数据,然后再写入目标文件。
        byte[] cache = new byte[1024];

        try {
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(destFile);
            // 缓冲输入流
            bufferIn = new BufferedInputStream(in);
            // 缓冲输出流
            bufferOut = new BufferedOutputStream(out);

            // 数据流转
            int data;
            // 当读取到文件末尾(即data为-1)时,循环结束。
            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);
                }
            }
        }
    }
}

字符流操作

文件流的操作是基于文件的字节 实现的。字符流的操作提供了另一种通过一行字符的形式操作数据。

再文件复制时,它会将一整行的字符一次性复制过去。

它的语法流程如下

首先,定义两个File对象,srcFile和destFile。这两个对象分别代表了源文件(我们要从中读取数据的文件)和目标文件(我们要写入数据的文件)。

arduino 复制代码
// 数据源对象
File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
// 数据目的地对象
File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");

然后,创建了两个流对象,reader和writer。这两个对象分别用于从源文件读取数据和向目标文件写入数据。

ini 复制代码
BufferedReader reader = null;  
PrintWriter writer = null;

接着,使用reader读取源文件的内容,而writer会向目标文件写入内容。

php 复制代码
try {  
    reader = new BufferedReader(new FileReader(srcFile));  
    writer = new PrintWriter(destFile);  
    ...  
} catch (IOException e) {  
    throw new RuntimeException(e);  
}

在try块中,读取源文件的内容。每次读取一行,直到文件结束(也就是没有更多的行可以读取)。每读取一行,我们都会打印这一行(在控制台输出),并且写入到目标文件。

arduino 复制代码
while ((line = reader.readLine()) != null){  
    System.out.println(line);  // 打印到控制台  
    writer.println(line);      // 写入到目标文件  
}

在读取和写入操作结束后,我们调用writer.flush()方法,确保所有待写入的数据都被立即写入到目标文件。

ini 复制代码
writer.flush();

完整代码如下:

java 复制代码
import java.io.*;

public class IO_Copy {
    public static void main(String[] args) {
        // 数据源对象
        File srcFile = new File("D:\Code\JAVA\collection\src\Data\testData.txt");
        // 数据目的地对象
        File destFile = new File("D:\Code\JAVA\collection\src\Data\testData_copy.txt");

        // 字符输入流(管道对象)
        BufferedReader reader = null;
        // 字符输出流(管道对象)
        PrintWriter writer = null;

        try {
            reader = new BufferedReader(new FileReader(srcFile));
            writer = new PrintWriter(destFile);


            // 读取文件的一行数据(字符串)
            String line = null;

            while ((line = reader.readLine()) != null){
                System.out.println(line);  // Hello
                writer.println(line);
            }
            // 刷写数据
            writer.flush();

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
相关推荐
海绵波波1071 小时前
flask后端开发(1):第一个Flask项目
后端·python·flask
AI人H哥会Java3 小时前
【Spring】控制反转(IoC)与依赖注入(DI)—IoC容器在系统中的位置
java·开发语言·spring boot·后端·spring
凡人的AI工具箱3 小时前
每天40分玩转Django:Django表单集
开发语言·数据库·后端·python·缓存·django
奔跑草-4 小时前
【数据库】SQL应该如何针对数据倾斜问题进行优化
数据库·后端·sql·ubuntu
中國移动丶移不动4 小时前
Java 并发编程:原子类(Atomic Classes)核心技术的深度解析
java·后端
Q_19284999065 小时前
基于Spring Boot的旅游推荐系统
spring boot·后端·旅游
愤怒的代码5 小时前
Spring Boot对访问密钥加密解密——RSA
java·spring boot·后端
美美的海顿5 小时前
springboot基于Java的校园导航微信小程序的设计与实现
java·数据库·spring boot·后端·spring·微信小程序·毕业设计
愤怒的代码5 小时前
Spring Boot中幂等性的应用
java·spring boot·后端
xiaocaibao7776 小时前
编程语言的软件工程
开发语言·后端·golang