热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java文件操作类效率对比

nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd

前言

众所周知,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             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             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             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             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             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             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(1/kn),其中不同的类的k不同,导致了最终巨大的差异。

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

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

附件

本次测试数据结果(若看不清,可以下载到本地看)

#

 


推荐阅读
  • 本文介绍了在Python中使用zlib模块进行字符串的压缩与解压缩的方法,并探讨了其在内存优化方面的应用。通过压缩存储URL等长字符串,可以大大降低内存消耗,虽然处理时间会增加,但是整体效果显著。同时,给出了参考链接,供进一步学习和应用。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了使用Python解析C语言结构体的方法,包括定义基本类型和结构体类型的字典,并提供了一个示例代码,展示了如何解析C语言结构体。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 代理模式的详细介绍及应用场景
    代理模式是一种在软件开发中常用的设计模式,通过在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象进行访问,从而简化系统的复杂性。代理模式可以根据不同的使用目的分为远程代理、虚拟代理、Copy-on-Write代理、保护代理、防火墙代理、智能引用代理和Cache代理等几种。本文将详细介绍代理模式的原理和应用场景。 ... [详细]
author-avatar
广东淡水未央
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有