Java中使用I/O Stream对文件进行读写操作

引言

        绝大部分程序都会有导入和导出的功能需求,要实现这个功能我们就需要先了解两个概念。一、IO:输入和输出,即Java程序与外界的交互,它使程序能够读取外部数据和将内部数据写出到外部。二、I/O Stream:输入输出流,Java程序执行IO操作的具体机制,流会将不同来源和目标的数据进行统一的抽象,按照数据传输的单位分为两大类,字节流和字符流。下面我将深入解析这里提到的概念和正确的使用方式

概念

字节流

        定义:以字节为单位进行读写操作的数据流

        使用场景:可以处理任意类型的数据,主要处理二进制数据,如图片、音频、视频等文件

  • InputStream:所有字节输入流的基类
  • OutputStream:所有字节输出流的基类

字符流

        定义:以字符为单位进行读写操作的数据流

        使用场景:用于处理文本类型的数据

  • Reader:所有字符输入流的基类
  • Writer:所有字符输出流的基类

IO模型

BIO

        定义:阻塞式输入输出,传统的IO模型,基于字节流和字符流

        特点:当用户线程发起IO操作时,需要等待操作系统系统内核返回结果后才能做其他任务

        优点:简单易用

        缺点:高并发场景会导致程序性能骤降

NIO

        定义:非阻塞式输入输出,java1.4版本引入的新IO模型,它的出现是为了解决BIO的缺陷,基于通道(类似于流,可以进行异步非阻塞操作)和缓冲区(用于和通道进行交互,读写数据)

        特点,当用户线程发起IO操作时,不需要等待操作系统系统内核返回结果就可以执行其他任务,期间会轮询查看IO操作的结果

        优点:不会阻塞,提高系统性能,它还有一个核心组件,Selector:用于管理多个通道的IO事件,即一个线程可以监听多个通道,这使得NIO模型能够高效地处理高并发连接

AIO

        定义:异步输入输出,java7引入地新模型,基于NIO模型

        特点:当用户线程发起IO操作时,不需要等待操作系统系统内核返回结果就可以执行其他任务,也不需要轮询查看IO操作的结果,因为IO操作完成时会以回调的方式通知相应线程

        优点:不会阻塞,提高系统性能,实时性高

对IO模型的描述涉及到计算机系统中的很多概念,因此我查阅了很多相关资料,以我的理解画了一张IO操作流程图,帮助你理解IO操作的原理

代码示例

工具类

/**
 * IO工具类
 * 使用缓冲字符输入流提高读写性能
 * 使用java7特性,自动管理资源
 * @author muze
 */
@Slf4j
public class IOUtil {
    /**
     * 字符输出流
     * 输出内容到文本文件
     * txt文件
     * @param writeContent 输出的内容
     * @param outputPath 输出路径
     */
    public static void outputContentToTextFile(String writeContent, String outputPath) {
        // 创建缓冲字符输出流
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputPath))) {
            // 输出内容
            bw.write(writeContent);
        } catch (IOException e) {
            log.error("IO异常:", e);
        }
    }

    /**
     * 字符输入流
     * 文本文件内容输入
     * txt文件
     * @param inputPath 输入路径
     */
    public static void textFileContentInput(String inputPath) {
        // 创建缓冲字符输入流
        try (BufferedReader br = new BufferedReader(new FileReader(inputPath))) {
            // 用于记录每行字符串
            String line;
            while ((line = br.readLine()) != null) {
                // 转成字符打印看看
                System.out.print(line);
            }
        } catch (IOException e) {
            log.error("IO异常:", e);
        }
    }

    /**
     * 字符输入输出流
     * 输出内容到文本文件并输入
     * txt文件
     * @param writeAndInputContent 输出并输入的内容
     * @param outputPath 输出路径
     */
    public static void outputContentToTextFileAndInput(String writeAndInputContent, String outputPath) {
        // 创建缓冲字符输入和缓冲字符输出流
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputPath));
             BufferedReader br = new BufferedReader(new FileReader(outputPath))) {
            // 输出内容
            bw.write(writeAndInputContent);
            // 用于记录每行字符串
            String line;
            while ((line = br.readLine()) != null) {
                // 转成字符打印看看
                System.out.print(line);
            }
        } catch (IOException e) {
            log.error("IO异常:", e);
        }
    }

    /**
     * 字节输入流
     * 非文本文件内容输入
     * jpg文件
     * @param inputPath 输入地址
     */
    public static void nonTextFileContentInput(String inputPath) {
        // 创建缓冲字节输入流
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputPath))) {
            // 输入所有字节
            byte[] bytes = bis.readAllBytes();
            // 打印看看
            System.out.println(new String(bytes));
        } catch (IOException e) {
            log.error("IO异常:", e);
        }
    }

    /**
     * 字节输入输出流
     * 非文本文件内容输入并输出
     * jpg文件
     * @param inputPath 输入地址
     * @param outputPath 输出地址
     */
    public static void nonTextFileContentInputAndOutput(String inputPath, String outputPath) {
        // 创建缓冲字节输入流和缓冲字节输出流
        try (FileInputStream fis = new FileInputStream(inputPath);
             FileOutputStream fos = new FileOutputStream(outputPath)) {
            // 输入所有字节
            byte[] readBytes = fis.readAllBytes();
            // 输出所有字节
            fos.write(readBytes);
        } catch (IOException e) {
            log.error("IO异常:", e);
        }
    }
}

测试类

/**
 * IO测试
 * @author muze
 */
@SpringBootTest
public class IOTest {
    /**
     * 测试输出内容到文本文件
     */
    @Test
    public void testOutputContentToTextFile() {
        String writeContent = "测试文本文件输出内容";
        String outputPath = "src/test/resources/测试文本文件内容输出.txt";
        IOUtil.outputContentToTextFile(writeContent, outputPath);
    }

    /**
     * 测试文本文件内容输入
     */
    @Test
    public void testTextFileContentInput() {
        String inputPath = "src/test/resources/测试文本文件内容输出.txt";
        IOUtil.textFileContentInput(inputPath);
    }

    /**
     * 测试输出内容到文本文件并输入
     */
    @Test
    public void testOutputContentToTextFileAndInput() {
        String writeAndInputContent = "测试文本文件输出并输入的内容";
        String outputPath = "src/test/resources/测试文本文件输出并输入.txt";
        IOUtil.outputContentToTextFileAndInput(writeAndInputContent, outputPath);
    }

    /**
     * 测试非文本文件内容输入
     */
    @Test
    public void testNonTextFileContentInput() {
        String inputPath = "src/test/resources/测试jpg文件输入.jpg";
        IOUtil.nonTextFileContentInput(inputPath);
    }

    /**
     * 测试非文本文件内容输入并输出
     */
    @Test
    public void testNonTextFileContentInputAndOutput() {
        String inputPath = "src/test/resources/测试jpg文件输入.jpg";
        String outputPath = "src/test/resources/测试jpg文件输入并输出.jpg";
        IOUtil.nonTextFileContentInputAndOutput(inputPath, outputPath);
    }
}

测试结果

注意事项

  1. 关闭流:在使用完流后,需要关闭它来释放资源,代码示例中使用java7特性try-with-resource语句自动关闭流
  2. 异常处理:IO操作时,可能会出现各种IO异常,所以,我们需要捕获进行妥善处理
  3. 性能优化:使用缓冲流提高读写性能,代码使用中使用Buffered缓冲流,使用默认的缓冲区,也可以设置缓冲区的大小,但请注意大小因业务而定,过大会占用较多内存资源
  4. 字符编码:字节流本身不涉及字符编码问题,但在处理文本文件时也需要注意字符编码的选择,字符流处理文本文件时应选择合适的编码以避免乱码问题

总结

        本文深入讲解了Java中IO的相关概念和简单且优雅的工具类封装并调用测试,我相信大家已经对IO有了一定程度的了解,赶紧动手试试吧,希望这篇文章能够对你有所帮助 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值