【BIO 、NIO 、AIO 三种方式实现读取文件】

1、BIO

BIO(Blocking I/O)模式,也就是阻塞式I/O,

  • 主要特点是每次读取操作都会阻塞线程,直到数据准备好才会返回数据,因此会导致线程阻塞和资源浪费,适用于数据量较小的场景。
  • 适用于数据量较小的场景,但对于大文件来说,读取整个文件可能会导致内存占用过高。在大文件场景下,建议采用NIO或AIO模式来进行优化。
package com.lfsun.main.basic.myio;

import com.lfsun.common.util.IOUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 *
 * BIO(Blocking I/O)模式,也就是阻塞式I/O,
 * 主要特点是每次读取操作都会阻塞线程,直到数据准备好才会返回数据,因此会导致线程阻塞和资源浪费,适用于数据量较小的场景。
 *
 *
 *
 * 适用于数据量较小的场景,但对于大文件来说,读取整个文件可能会导致内存占用过高。在大文件场景下,建议采用NIO或AIO模式来进行优化。
 * @author Administrator
 */
public class BioFileReader {
    public static void main(String[] args) {
        // 指定要读取的文件路径 ,将要读取的文件路径通过IOUtils.getClasspathFilePath()方法获取
        File file = new File(IOUtils.getClasspathFilePath("test.txt"));
        // 通过创建 FileInputStream 实例来读取文件
        try (FileInputStream fis = new FileInputStream(file)) {
            // 创建缓冲区用于存储读取的数据
            byte[] buffer = new byte[1024];

            // 循环读取文件内容并打印到控制台
            int bytesRead;
            // read() 方法会尝试从输入流中读取 buffer.length 个字节的数据,并将其存储到缓冲区中。
            // 如果成功读取了数据,则返回实际读取的字节数;如果已经到达输入流的末尾,则返回 -1。如果出现了异常,则会抛出 IOException。
            while ((bytesRead = fis.read(buffer)) != -1) {
                // 将缓冲区中的数据转换为字符串并打印到控制台
                String content = new String(buffer, 0, bytesRead);
                System.out.print(content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("end!");
    }
}

2、NIO

NIO(Non-blocking I/O)模式,也就是非阻塞式I/O,

  • 主要特点是读写操作不会阻塞线程,线程可以继续执行其他操作,因此可以提高资源利用率和系统吞吐量,适用于大量数据传输的场景。
package com.lfsun.main.basic.myio;

import com.lfsun.common.util.IOUtils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * NIO(Non-blocking I/O)模式,也就是非阻塞式I/O,
 * 主要特点是读写操作不会阻塞线程,线程可以继续执行其他操作,因此可以提高资源利用率和系统吞吐量,适用于大量数据传输的场景。
 *
 * 一个使用 NIO 读取文件的示例程序。
 * @author Administrator
 */
public class NioFileReader {
    public static void main(String[] args) {
        // 指定要读取的文件路径
        Path filePath = Paths.get(IOUtils.getClasspathFilePath("test.txt"));
        // 创建了一个FileChannel实例并打开指定的文件,使用 StandardOpenOption.READ 选项表示以只读模式打开文件。
        try (FileChannel fileChannel = FileChannel.open(filePath, StandardOpenOption.READ)) {
            // 创建了一个 ByteBuffer实例作为缓冲区,并指定缓冲区的大小为1024字节。
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            // 循环读取文件内容并打印到控制台, 返回值为读取的字节数,当返回值为-1时表示已经读到文件的末尾。
            while (fileChannel.read(buffer) != -1) {
                // 切换缓冲区的读写模式,使用 flip 方法将缓冲区从写模式切换到读模式。
                buffer.flip();

                // 使用 NIO 的 Charset和 StandardCharsets类来进行字符集的转换
                String content = StandardCharsets.UTF_8.decode(buffer).toString();
                System.out.print(content);

                // 使用clear方法将缓冲区的指针重置为初始位置,但是缓冲区中的数据并没有被清空,下次读取会覆盖之前的数据。
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("end!");
    }
}


3、AIO

AIO(Asynchronous I/O)模式,也就是异步I/O,

  • 主要特点是读写操作不会阻塞线程,读写操作完成后会异步通知线程,因此可以更好地利用系统资源,适用于大量并发请求的场景。
package com.lfsun.main.basic.myio;

import com.lfsun.common.util.IOUtils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * AIO(Asynchronous I/O)模式,也就是异步I/O,
 * 主要特点是读写操作不会阻塞线程,读写操作完成后会异步通知线程,因此可以更好地利用系统资源,适用于大量并发请求的场景。
 *
 * 该类演示了如何使用 Java NIO2 的异步文件 IO API 读取文件。
 * @author Administrator
 */
public class AioFileReader {

    public static void main(String[] args) {
        // 指定要读取的文件路径
        Path filePath = Paths.get(IOUtils.getClasspathFilePath("test.txt"));

        try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(filePath, StandardOpenOption.READ)) {
            // 创建缓冲区用于存储读取的数据
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            // 循环异步读取文件
            long position = 0;
            while (true) {
                Future<Integer> future = fileChannel.read(buffer, position);

                // 等待读取完成
                while (!future.isDone()) {
                    System.out.println("正在读取文件...");
                }

                int bytesRead = future.get();
                // 当返回值为-1时表示已经读到文件的末尾。
                if (bytesRead == -1) {
                    break;
                }

                // 将缓冲区从写模式切换到读模式
                buffer.flip();

                // 将缓冲区中的数据转换为字符串并打印到控制台
                String content = StandardCharsets.UTF_8.decode(buffer).toString();
                System.out.print(content);

                // 清空缓冲区以便下次读取
                buffer.clear();

                // 更新下一次读取的位置
                position += bytesRead;
            }
        } catch (IOException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("end!");
    }
}

从类路径下获取文件的路径

/**
     * 从类路径下获取文件的路径
     *
     * @param filename 文件名
     * @return 文件的路径
     * @throws IllegalArgumentException 如果filename为null或找不到文件
     */
    public static String getClasspathFilePath(String filename) throws IllegalArgumentException {
        if (filename == null) {
            throw new IllegalArgumentException("文件名不能为null");
        }
        // 获取类加载器
        ClassLoader classLoader = IOUtils.class.getClassLoader();
        // 获取文件的 URL
        URL url = classLoader.getResource(filename);
        if (url == null) {
            throw new IllegalArgumentException("文件找不到: " + filename);
        }
        // URL 转换为 Path,使用Paths而不是File:Paths类提供了更好的API来处理文件路径,可以提供更好的可读性和代码可维护性。
        Path path;
        try {
            path = Paths.get(url.toURI());
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("无效的 URL: " + url, e);
        }
        // 返回文件路径
        return path.toAbsolutePath().toString();
    }

你可能感兴趣的:(记录,Java,java)