java四种文件读写方式及性能比较

Posted braska

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java四种文件读写方式及性能比较相关的知识,希望对你有一定的参考价值。

测试代码

package com.boot.demo.test.io;

import java.io.*;
import java.lang.reflect.Method;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * @author braska
 * @date 2020/3/19
 **/
public class FileTest {

    public static void fileStream(String sourceFile, String targetFile) {
        File file = new File(targetFile);
        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(file)) {
            byte[] bytes = new byte[1024 * 1024];
            int len;
            while ((len = fis.read(bytes)) > 0) {
                fos.write(bytes, 0, len);
            }
        } catch (Exception e) {

        }
    }

    public static void bufferStream(String sourceFile, String targetFile) {
        try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(Paths.get(sourceFile)));
             BufferedOutputStream bos =
                     new BufferedOutputStream(Files.newOutputStream(Paths.get(targetFile),
                             StandardOpenOption.CREATE,
                             StandardOpenOption.TRUNCATE_EXISTING,
                             StandardOpenOption.WRITE))) {
            byte[] bytes = new byte[1024 * 1024];
            int len;
            while ((len = bis.read(bytes)) > 0) {
                bos.write(bytes, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void randomFile(String sourceFile, String targetFile) {
        try (RandomAccessFile read = new RandomAccessFile(sourceFile, "r");
             RandomAccessFile write = new RandomAccessFile(targetFile, "rw")) {
            byte[] bytes = new byte[1024 * 1024];
            int len;
            while ((len = read.read(bytes)) > 0) {
                write.write(bytes, 0, len);
            }
        } catch (Exception e) {

        }
    }


    public static void memoryMap(String sourceFile, String targetFile) {
        try (FileChannel rc = FileChannel.open(Paths.get(sourceFile));
             FileChannel wc = FileChannel.open(Paths.get(targetFile),
                     StandardOpenOption.CREATE,
                     StandardOpenOption.READ,
                     StandardOpenOption.TRUNCATE_EXISTING,
                     StandardOpenOption.WRITE)) {
            long copy = 1L << 30;
            long cur = 0;
            long fileLength = rc.size();
            while (cur < fileLength) {
                MappedByteBuffer rMap = rc.map(FileChannel.MapMode.READ_ONLY, cur, copy);
                MappedByteBuffer wMap = wc.map(FileChannel.MapMode.READ_WRITE, cur, copy);
                for (int i = 0; i < copy; i++) {
                    byte b = rMap.get(i);			//从源文件读取字节
                    wMap.put(i, b);					//把字节写到目标文件中
                }
                System.gc();				//手动调用 GC		<必须的,否则出现异常>
                System.runFinalization();
                cur += copy;
                copy = cur + copy > fileLength ? (fileLength - cur) : copy;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void clean(final MappedByteBuffer buffer) throws Exception {
        if (buffer == null) {
            return;
        }
        buffer.force();
        AccessController.doPrivileged(new PrivilegedAction<Object>() {//Privileged特权
            @Override
            public Object run() {
                try {
                    // System.out.println(buffer.getClass().getName());
                    Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);
                    getCleanerMethod.setAccessible(true);
                    sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod.invoke(buffer, new Object[0]);
                    cleaner.clean();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    private static String buildFilePath(String path, String fileName, String extension) {
        return String.format("%s%s.%s", path, fileName, extension);
    }

    public static void main(String[] args) {
/*        String path = "F:\workspace\demo\";
        String extension = "hprof";
        // 30M文件
        String sourceFile = buildFilePath(path, "01", extension);*/

/*        String path = "E:\software\";
        String extension = "exe";
        // 460M文件
        String sourceFile = buildFilePath(path, "Anaconda3-2019.10-Windows-x86_64", extension);*/

        String path = "E:\software\";
        String extension = "zip";
        // 1.47G文件
        String sourceFile = buildFilePath(path, "software", extension);
        String targetFile;
        long start;

/*        targetFile = buildFilePath(path, "target_file_stream", extension);
        start = System.currentTimeMillis();
        FileTest.fileStream(sourceFile, targetFile);
        System.out.println("file stream used time:" + (System.currentTimeMillis() - start));*/

/*        targetFile = buildFilePath(path, "target_buffer_stream", extension);
        start = System.currentTimeMillis();
        FileTest.bufferStream(sourceFile, targetFile);
        System.out.println("buffer stream used time:" + (System.currentTimeMillis() - start));*/

/*        targetFile = buildFilePath(path, "target_random_file", extension);
        start = System.currentTimeMillis();
        FileTest.randomFile(sourceFile, targetFile);
        System.out.println("random file used time:" + (System.currentTimeMillis() - start));*/


        targetFile = buildFilePath(path, "target_memory_map", extension);
        start = System.currentTimeMillis();
        FileTest.memoryMap(sourceFile, targetFile);
        System.out.println("memory map used time:" + (System.currentTimeMillis() - start));
    }
}

测试结果

文件大小读写方式耗时
30M 普通文件流 50-60 ms
缓存流 32-35ms
随机文件方式 40-50ms
内存映射文件 50-60ms
461M 普通文件流 1300-2300 ms
缓存流 1700-2000 ms
随机文件方式 1300-3000 ms
内存映射文件 890-1000 ms
1.47G 普通文件流 11s
缓存流 9s
随机文件方式 10s
内存映射文件 1.6s

以上是关于java四种文件读写方式及性能比较的主要内容,如果未能解决你的问题,请参考以下文章

Java学习笔记文件和Excel操作工具类

java程序中比较常见的四种判断是不是为空的性能优化比较

Java8字符串分割的几种方式及性能比较

PHP读写XML文件

domSAXJdomdom4j四种解析xml方式简单总结

IO---Java 不同读写方式的IO性能