热门标签 | 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不同,导致了最终巨大的差异。

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

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

附件

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

#

 


推荐阅读
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • 在VS2013中编译FFMPEG时遇到的问题及解决方案
    在使用VS2013编译旧版本FFMPEG库时遇到了一些问题,因为官方并未提供预编译的LIB和DLL文件。由于对Linux环境不熟悉,只能在Windows环境下进行配置和编译。具体步骤如下:首先,下载FFMPEG的源代码;然后,安装必要的编译工具和依赖项;接着,配置Visual Studio 2013的项目设置;最后,解决编译过程中出现的各种错误和警告。通过这些步骤,最终成功编译出所需的FFMPEG库文件。 ... [详细]
  • `chkconfig` 命令主要用于管理和查询系统服务在不同运行级别中的启动状态。该命令不仅能够更新服务的启动配置,还能检查特定服务的当前状态。通过 `chkconfig`,管理员可以轻松地控制服务在系统启动时的行为,确保关键服务正常运行,同时禁用不必要的服务以提高系统性能和安全性。本文将详细介绍 `chkconfig` 的各项参数及其使用方法,帮助读者更好地理解和应用这一强大的系统管理工具。 ... [详细]
  • Windows环境下RabbitMQ安装详尽指南
    Windows环境下RabbitMQ安装详尽指南 ... [详细]
  • 作为软件工程专业的学生,我深知课堂上教师讲解速度之快,很多时候需要课后自行消化和巩固。因此,撰写这篇Java Web开发入门教程,旨在帮助初学者更好地理解和掌握基础知识。通过详细记录学习过程,希望能为更多像我一样在基础方面还有待提升的学员提供有益的参考。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • MySQL 8.0 MGR 自动化部署与配置:DBA 和开源工具的高效解决方案
    MySQL 8.0 MGR 自动化部署与配置:DBA 和开源工具的高效解决方案 ... [详细]
  • CTF竞赛中文件上传技巧与安全绕过方法深入解析
    CTF竞赛中文件上传技巧与安全绕过方法深入解析 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • Vue应用预渲染技术详解与实践 ... [详细]
  • 本文详细介绍了使用 Python 进行 MySQL 和 Redis 数据库操作的实战技巧。首先,针对 MySQL 数据库,通过 `pymysql` 模块展示了如何连接和操作数据库,包括建立连接、执行查询和更新等常见操作。接着,文章深入探讨了 Redis 的基本命令和高级功能,如键值存储、列表操作和事务处理。此外,还提供了多个实际案例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 在嵌入式Linux系统中,性能低下通常由CPU、内存和I/O三个关键因素引起。为了有效提升系统性能,首先需要识别并定位性能瓶颈。通过综合分析这些瓶颈,可以采取针对性的优化措施,如调整内核参数、优化算法和改进数据结构等,从而显著提高系统的整体性能。 ... [详细]
  • 将JavaScript文件嵌入HTML文档是Web开发中的基本操作。常见的方法是通过在HTML文件中使用``标签来引用外部的.js文件。这种方法不仅保持了代码的整洁性,还便于管理和维护。此外,还可以利用模块化脚本和异步加载技术进一步提升页面性能。 ... [详细]
  • 本文介绍了如何在 Windows 系统上利用 Docker 构建一个包含 NGINX、PHP、MySQL、Redis 和 Elasticsearch 的集成开发环境。通过详细的步骤说明,帮助开发者快速搭建和配置这一复杂的技术栈,提升开发效率和环境一致性。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
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社区 版权所有