文件读写注意事项

确保文件中字符的字符集和字符流的字符集是一致

//确保文件中字符的字符集和字符流的字符集是一致的,否则可能产生乱码。
private static void right1() throws IOException {
    char[] chars = new char[10];
    String content = "";
    try (FileInputStream fileInputStream = new FileInputStream("hello.txt");
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, Charset.forName("GBK"))) {
        int count;
        while ((count = inputStreamReader.read(chars)) != -1) {
            content += new String(chars, 0, count);
        }
    }
    log.info("result: {}", content);
}

Files类流式处理注意事项

//注意1:(使用JDK1.7推出的Files类的readAllLines方法,此种方法读取超出内存大小的大文件时会出现OOM,源码中读到的内容放在List<String>中返回,内存无法容纳就会OOM)
log.info("result: {}", Files.readAllLines(Paths.get("hello.txt"), Charset.forName("GBK")).stream().findFirst().orElse(""));
//注意2:使用Files类静态方法(lines方法返回的Stream<String>,按需读取到内存)进行文件操作(注意释放文件句柄),此种方法需要释放资源(关闭文件)
LongAdder longAdder = new LongAdder();
IntStream.rangeClosed(1, 1000000).forEach(i -> {
    try {
        Files.lines(Paths.get("demo.txt")).forEach(line -> longAdder.increment());
    } catch (IOException e) {
        e.printStackTrace();
    }
});
log.info("total : {}", longAdder.longValue());  
//注意3:使用try-with-resources配合,确保流的close方法可以调用释放资源(同理Files类中其他返回Stream包装对象的方法流式处理也需要释放资源)
LongAdder longAdder = new LongAdder();
IntStream.rangeClosed(1, 1000000).forEach(i -> {
    try (Stream<String> lines = Files.lines(Paths.get("demo.txt"))) {
        lines.forEach(line -> longAdder.increment());
    } catch (IOException e) {
        e.printStackTrace();
    }
});
log.info("total : {}", longAdder.longValue());
//注意5:Java的File类和Files类提供的文件复制、重命名、删除等操作,都不是原子性的
//因为线程不安全,并且文件类操作基本都是调用操作系统本身的API,一般来说这些文件API并不像数据库有事务机制(很难办到)文档中有提到。

读写文件需要考虑设置缓冲区

//文件IO处理,使用合适的缓冲区提高性能,使批量读写减少IO次数
//额外使用一个8KB缓冲,再使用BufferedInputStream和BufferedOutputStream
private static void bufferedStreamBufferOperation() throws IOException {
    try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("src.txt"));
         BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("dest.txt"))) {
        byte[] buffer = new byte[8192];
        int len = 0;
        while ((len = bufferedInputStream.read(buffer)) != -1) {
            bufferedOutputStream.write(buffer, 0, len);
        }
    }
}
//ns % Task name
//117807808 007% bufferedStreamBufferOperation

FileChannel流转发

//对于类似的文件复制操作,如果希望有更高性能,可以使用 FileChannel 的 transfreTo 方法进行流的复制。
//在一些操作系统(比如高版本的 Linux 和 UNIX)上可以实现 DMA(直接内存访问),
//也就是数据从磁盘经过总线直接发送到目标文件,无需经过内存和 CPU 进行数据中转:
private static void fileChannelOperation() throws IOException {
    FileChannel in = FileChannel.open(Paths.get("src.txt"), StandardOpenOption.READ);
    FileChannel out = FileChannel.open(Paths.get("dest.txt"), CREATE, WRITE);
    in.transferTo(0, in.size(), out);
}

注意事项

//文件操作因为涉及操作系统和文件系统的实现,JDK 并不能确保所有 IO API 在所有平台的逻辑一致性;
//因此、代码迁移到新的操作系统或文件系统时,要重新进行功能测试和性能测试。

 

上一篇:python 使用open3d 显示pcd点云


下一篇:SVM算法应用--人脸表情识别