美文网首页程序员之言Java
Java基础—Java文件操作流处理效率对比

Java基础—Java文件操作流处理效率对比

作者: java面试笔试 | 来源:发表于2018-09-10 15:57 被阅读0次

    众所周知,Java中有多种针对文件的操作类,以面向字节流和字符流可分为两大类,这里以写入为例:

    面向字节流的:FileOutputStream和BufferedOutputStream

    面向字符流的:FileWriter和BufferedWriter

    近年来发展出New I/O ,也叫NIO,里面又包装了两个类:NewOutputStream 和 NewBufferedWriter。现在,我们建立测试程序,比较这些类写入文件的性能。

    机器配置

    Processor Name: Intel Core i7

    Processor Speed: 2.2 GHz

    Number of Processors: 1

    Total Number of Cores: 4

    L2 Cache (per Core): 256 KB

    L3 Cache: 6 MB

    Memory: 16 GB

    测试程序

    纵向比较:几种文件操作类向文件中写入相同行数的内容(每行内容均为“写入文件Data\n”),比较其耗费时间。

    横向比较:对于同一个文件操作类,比较写入不同行数内容情况下所耗费时间;本文以2的次方指数级增长行数。

    import java.io.File;

    import java.io.FileOutputStream;

    import java.io.*;

    import java.nio.file.Files;

    import java.nio.file.Paths;

    public class testFileIO {

        public static void testDriver () throws IOException {

            int maxlineNum = 100000001;//写入文件的最大行数

            int startlineNum = 1;//写入文件的行数

            int Multiplying = 2;//行数增长倍率

            long begin = 0L;

            long end = 0L;

            //将时间统计写入文件Result.txt中

            FileWriter fileWriter = new FileWriter("./Result.txt", true);

            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            System.out.println("Test FileOutputStream begin.");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testFileOutputStream(lineNum);

                end = System.currentTimeMillis();

                long timeElapse_FileOutputStream = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_FileOutputStream)+"\t");

            }

            System.out.println("Test FileOutputStream end.\n");

            System.out.println("Test BufferedOutputStream begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testBufferedOutputStream(lineNum);

                end = System.currentTimeMillis();

                long timeElapse_BufferedOutputStream = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_BufferedOutputStream)+"\t");

            }

            System.out.println("Test BufferedOutputStream end.\n");

            System.out.println("Test FileWriter begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testFileWriter(lineNum);

                end = System.currentTimeMillis();

                long timeElapse_FileWriter = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_FileWriter)+"\t");

            }

            System.out.println("Test FileWriter end.\n");

            System.out.println("Test BufferedWriter begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testBufferedWriter(lineNum);

                end = System.currentTimeMillis();

                long timeElapse_BufferedWriter = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_BufferedWriter)+"\t");

            }

            System.out.println("Test BufferedWriter end.\n");

            System.out.println("Test NewOutputStream begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testNewOutputStream(lineNum);

                end = System.currentTimeMillis();

                long timeElapse_NewOutputStream = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_NewOutputStream)+"\t");

            }

            System.out.println("Test NewOutputStream end.\n");

            System.out.println("Test NewBufferedWriter begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testNewBufferedWriter(lineNum);

                end = System.currentTimeMillis();

                long timeElapse_NewBufferedWriter = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_NewBufferedWriter)+"\t");

            }

            System.out.println("Test NewOutputStream end.\n");

            bufferedWriter.close();

        }

        /************************** I/O *****************************/

        //面向字节

        public static void testFileOutputStream (int lineNum) throws IOException {

            FileOutputStream fileOutputStream = new FileOutputStream(new File("./testFileOutputStream.txt"));

            while (--lineNum > 0) {

                fileOutputStream.write("写入文件Data\n".getBytes());

            }

            fileOutputStream.close();

        }

        public static void testBufferedOutputStream (int lineNum) throws IOException {

            FileOutputStream fileOutputStream = new FileOutputStream(new File("./testBufferedOutputStream.txt"));

            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

            while (--lineNum > 0) {

                bufferedOutputStream.write("写入文件Data\n".getBytes());

            }

            bufferedOutputStream.close();

        }

        //面向字符

        public static void testFileWriter (int lineNum) throws IOException {

            FileWriter fileWriter = new FileWriter("./testFileWriter.txt");

            while (--lineNum > 0) {

                fileWriter.write("写入文件Data\n");

            }

            fileWriter.close();

        }

        public static void testBufferedWriter (int lineNum) throws IOException {

            FileWriter fileWriter = new FileWriter("./testBufferedWriter.txt");

            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            while (--lineNum > 0) {

                bufferedWriter.write("写入文件Data\n");

            }

            bufferedWriter.close();

        }

        /************************** NIO ****************************/

        public static void testNewOutputStream (int lineNum) throws IOException {

            OutputStream outputStream = Files.newOutputStream(Paths.get("./testNewOutputStream.txt"));

            while (--lineNum > 0) {

                outputStream.write("写入文件Data\n".getBytes());

            }

            outputStream.close();

        }

        public static void testNewBufferedWriter (int lineNum) throws IOException {

            BufferedWriter newBufferedReader = Files.newBufferedWriter(Paths.get("./testNewBufferedWriter.txt"));

            while (--lineNum > 0) {

                newBufferedReader.write("写入文件Data\n");

            }

            newBufferedReader.close();

        }

        public static void main (String[] args) throws IOException {

            //多次测试时可清空result.txt文件

            FileWriter fileWriter = new FileWriter("./Result.txt");

            testDriver();

        }

    }

    测试结果,如图所示:

    从上图可以看出,写入行数超过20W以上时,FileOutputStream和NewOutputStream耗费时间远远超出其他4个类。为了清晰,让我们放大其他4个类的图:

    可以看出,这4个类中,BufferWriter和NewBufferedWriter所耗费时间更少,但总体差别不是很大。

    让我们再来看看,写入26W行数据以下时的情况:

    可以看出,在数据量较小的情况下,这4个类所耗费时间的差异并不是很大,在更小的数据量下,它们的效率几乎没有差别。

    后记

    从以上分析可知(注意横坐标写入行数是指数级增加的),各个类的时间复杂度大致为O(k),其中不同的类的k不同,导致了最终巨大的差异。

    这里只给出了测试结果,并未分析其底层实现原理,欢迎评论区留言。

    另外,我没有在其他机器测试,有兴趣的小伙伴可以将自己的测试结果发出来,共同进步^_^。

    附件

    本次测试数据结果(若看不清,可以将浏览器字体放大,或下载到本地看)

    ~~~~~~~~~~分割线~~~~~~~~~

    评论区小伙伴“ andorxor”提出:

    XXXOutputStream是用来写二进制的,你把字符串转换成字节数组再写自然就慢了,主要慢在转换的过程。

    因此,将程序修改,提前把字符和字节内容都准备好,再次验证。新程序如下:

    import java.io.File;

    import java.io.FileOutputStream;

    import java.io.*;

    import java.nio.file.Files;

    import java.nio.file.Paths;

    public class testFileIO {

        public static void testDriver () throws IOException {

            int maxlineNum = 100000001;//写入文件的最大行数

            int startlineNum = 1;//写入文件的行数

            int Multiplying = 2;//行数增长倍率

            String contentChars = "写入文件Data\n";//每行的内容(字符流)

            byte[] contentBytes = "写入文件Data\n".getBytes();//每行的内容(字节流)

            long begin = 0L;

            long end = 0L;

            //将时间统计写入文件Result.txt中

            FileWriter fileWriter = new FileWriter("./Result.txt", true);

            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            System.out.println("Test FileOutputStream begin.");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testFileOutputStream(lineNum,contentBytes);

                end = System.currentTimeMillis();

                long timeElapse_FileOutputStream = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_FileOutputStream)+"\t");

            }

            System.out.println("Test FileOutputStream end.\n");

            System.out.println("Test BufferedOutputStream begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testBufferedOutputStream(lineNum,contentBytes);

                end = System.currentTimeMillis();

                long timeElapse_BufferedOutputStream = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_BufferedOutputStream)+"\t");

            }

            System.out.println("Test BufferedOutputStream end.\n");

            System.out.println("Test FileWriter begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testFileWriter(lineNum,contentChars);

                end = System.currentTimeMillis();

                long timeElapse_FileWriter = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_FileWriter)+"\t");

            }

            System.out.println("Test FileWriter end.\n");

            System.out.println("Test BufferedWriter begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testBufferedWriter(lineNum,contentChars);

                end = System.currentTimeMillis();

                long timeElapse_BufferedWriter = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_BufferedWriter)+"\t");

            }

            System.out.println("Test BufferedWriter end.\n");

            System.out.println("Test NewOutputStream begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testNewOutputStream(lineNum,contentBytes);

                end = System.currentTimeMillis();

                long timeElapse_NewOutputStream = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_NewOutputStream)+"\t");

            }

            System.out.println("Test NewOutputStream end.\n");

            System.out.println("Test NewBufferedWriter begin.");

            bufferedWriter.write("\n");

            for (int lineNum = startlineNum; lineNum < maxlineNum; lineNum *= Multiplying) {

                begin = System.currentTimeMillis();

                testNewBufferedWriter(lineNum,contentChars);

                end = System.currentTimeMillis();

                long timeElapse_NewBufferedWriter = end - begin;

                bufferedWriter.write(String.valueOf(timeElapse_NewBufferedWriter)+"\t");

            }

            System.out.println("Test NewOutputStream end.\n");

            bufferedWriter.close();

        }

        /************************** I/O *****************************/

        //面向字节

        public static void testFileOutputStream (int lineNum, byte[] content) throws IOException {

            FileOutputStream fileOutputStream = new FileOutputStream(new File("./testFileOutputStream.txt"));

            while (--lineNum > 0) {

                fileOutputStream.write(content);

            }

            fileOutputStream.close();

        }

        public static void testBufferedOutputStream (int lineNum, byte[] content) throws IOException {

            FileOutputStream fileOutputStream = new FileOutputStream(new File("./testBufferedOutputStream.txt"));

            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

            while (--lineNum > 0) {

                bufferedOutputStream.write(content);

            }

            bufferedOutputStream.close();

        }

        //面向字符

        public static void testFileWriter (int lineNum, String content) throws IOException {

            FileWriter fileWriter = new FileWriter("./testFileWriter.txt");

            while (--lineNum > 0) {

                fileWriter.write(content);

            }

            fileWriter.close();

        }

        public static void testBufferedWriter (int lineNum, String content) throws IOException {

            FileWriter fileWriter = new FileWriter("./testBufferedWriter.txt");

            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            while (--lineNum > 0) {

                bufferedWriter.write(content);

            }

            bufferedWriter.close();

        }

        /************************** NIO ****************************/

        public static void testNewOutputStream (int lineNum, byte[] content) throws IOException {

            OutputStream outputStream = Files.newOutputStream(Paths.get("./testNewOutputStream.txt"));

            while (--lineNum > 0) {

                outputStream.write(content);

            }

            outputStream.close();

        }

        public static void testNewBufferedWriter (int lineNum,String content) throws IOException {

            BufferedWriter newBufferedReader = Files.newBufferedWriter(Paths.get("./testNewBufferedWriter.txt"));

            while (--lineNum > 0) {

                newBufferedReader.write(content);

            }

            newBufferedReader.close();

        }

        public static void main (String[] args) throws IOException {

            //多次测试时可清空result.txt文件

            FileWriter fileWriter = new FileWriter("./Result.txt");

            testDriver();

        }

    }

    结果如图所示:

    可以看出和前面的案例几乎没有差异(图就不画了)。

    所以XXXOutputStream效率低的原因并不是字符串转换成字节数组,而是其本身的实现方式所致。

    公众号:javafirst

    作者:xiaoxi666

    https://www.cnblogs.com/xiaoxi666/p/9531893.html

    相关文章

      网友评论

        本文标题:Java基础—Java文件操作流处理效率对比

        本文链接:https://www.haomeiwen.com/subject/akbsgftx.html