Java IO精髓:高效块读写入技术深入解析

news2024/9/25 9:31:18

文件的复制

    首先我们先用昨天学习的知识来完成文件的复制,使用read和write方法来完成。

    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("./image.png");
        FileOutputStream fos = new FileOutputStream("./copy_image.png");
        int d;
        int num = 0;
        long startTime = System.currentTimeMillis();
//        d = fis.read();
//        fos.write(d+1);哪怕改一个值图片都无法正常显示
//如果直接修改数据流中的任意字节(如你尝试的fos.write(d+1);),这很可能导致生成的图片文件损坏,
// 因为图片的格式(如PNG, JPEG等)有严格的字节排列和数据结构要求。
// 一个字节的改动可能会破坏图片的头部信息、颜色表、像素数据或其他关键部分。
        while ((d = fis.read()) != -1) {
            fos.write(d);
            num++;
        }
        long endTime=System.currentTimeMillis();
        System.out.println("复制完毕");
        System.out.println(num);
        System.out.println("复制时间为:"+(endTime-startTime)+"毫秒");

        fis.close();
        fos.close();
    }

在昨天的学习中,我们学习了如何向文件中写入或者从文件中读取数据,但是在面临需要读入或者写出大量数据时,例如上面我们要复制一张图片,或者是一首歌,又或者是一个视频时,我们需要不断的用循环来调用read和write方法?很明显这样做很浪费性能,并且上述案例在复制文件时的读写效率是很低的。因为硬盘的特性,决定着硬盘的读写效率差,而单字节读 写就是在频繁调用硬盘的读写,从而产生了"木桶效应"。 为了解决这个问题,我们可以采取使用块读写的方式来复制文件,减少硬盘的实际读写的次数,从而提 高效率。

 

 块读入

InputStream定义了块读方法                                                        

int read(byte[ ] data)

一次性读取给定字节数组data总长度的字节量并存入到该数组中。 返回值表达实际读取到了多少字节。如果返回值为-1表达流读取到末尾了

 下面我将用拆分来详细解释块读入是如何运行的

            原文件内容:
            11001100 01010101 10101010 00111100 11001111 00110011 11101100
            --------------------------------------------------------------

            byte[] data = new byte[3];//长度为3的字节数组
            data:{00000000,00000000,00000000}
            int len=0;

            第一次调用:
            len = fis.read(data);//因为data长度为3,因此一次性读取3字节并存入该数组
            原文件内容:
            11001100 01010101 10101010 00111100 11001111 00110011 11101100
            ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
            连续读取3个字节
            data:{11001100,01010101,10101010}读取后数组内容就是读取到的内容
            len:3 len接收的返回值为整数,表示本次实际读取到了3个字节

            -----------------------------------------------------------------
            第二次调用:
            len = fis.read(data);//因为data长度为3,因此一次性读取3字节并存入该数组
            原文件内容:
            11001100 01010101 10101010 00111100 11001111 00110011 11101100
                                       ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
            连续读取3个字节
            data:{00111100,11001111,00110011}读取后数组内容就是读取到的内容
            len:3   len接收的返回值为整数,表示本次实际读取到了3个字节

            ----------------------------------------------------------------
            第三次调用:
            len = fis.read(data);//因为data长度为3,因此一次性读取3字节并存入该数组
            原文件内容:
            11001100 01010101 10101010 00111100 11001111 00110011 11101100
                                                                  ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
                                                                  应当读取3个,实际读取到1个
            连续读取3个字节
            data:{11101100,11001111,00110011}
                  本次读取  |--上次的旧数据---|

            len:1   len接收的返回值为整数,表示本次实际读取到了1个字节

            -----------------------------------------------------------------
            第四次调用:
            len = fis.read(data);//因为data长度为3,因此一次性读取3字节并存入该数组
            原文件内容:
            11001100 01010101 10101010 00111100 11001111 00110011 11101100
                                                                           ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
                                                                           本次没有数据可读(EOF)
            data:{11101100,11001111,00110011}
                  |------上次的旧数据--------|
            len:-1   已经是文件末尾了

块写出

OutputStream中定义了块写操作

void write(byte[ ] data)

一次性将给定字节数组data中的所有字节写出

 小问题

 在学习完上面的两个方法后相信你已经学会如何把这张图片去复制了,但是如果你去实践后,就会发现速度问题解决了,但是复制后的文件比原文件大一些。这是文件不一定是10240的倍数,这会导致最后 一次读取时是读不够10240的字节数的,那么data数组中就不是所有数据都是新数据了。此时如果在写 出时将data数组所有内容写出就会出现文件最后多出很多旧的数据。

我们用一张图片来解释

我们每次都是读入四个字节的数据,但是在复制到第四次也就是最后一次时只剩下紫色部分的数据,而显然这不能填满data数组的长度,因此再最后写入复制文件时后面的数据还是蓝色的也就是上次复制时剩下的旧数据。

解决 

使用OutputStream的另一个块写操作

void write(byte[] data,int offset,int len)

将给定数组data从offset处开始的连续len个字节一次性写

 我们来看看最后的解决

        FileInputStream fis = new FileInputStream("./image.png");
        FileOutputStream fos = new FileOutputStream("./copy_image02.png");
        byte[] data = new byte[1024 * 100];
        int len = 0;
        long start=System.currentTimeMillis();
        while ((len = fis.read(data)) != -1) {
            fos.write(data,0,len);
        }
        long end=System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"毫秒");
        fos.close();
        fis.close();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2077826.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV开发笔记(七十九):基于Stitcher类实现全景图片拼接

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141561865 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…

加速边缘智能技术落地!移远通信推出全功能ARM主板QSM560DR、QSM668SR系列

8月22日,全球领先的物联网整体解决方案供应商移远通信宣布,正式推出其两款全功能ARM主板——QSM560DR与QSM668SR系列。 作为智能设备开发与硬件设计的核心平台,这两款ARM主板以卓越的集成度和性能、广泛的兼容性以及丰富的功能接口&#xff0…

零基础学习人工智能—Python—Pytorch学习(八)

前言 本文介绍卷积神经网络的上半部分。 其实,学习还是需要老师的,因为我自己写文章的时候,就会想当然,比如下面的滑动窗口,我就会想当然的认为所有人都能理解,而实际上,我们在学习的过程中之所以卡顿的点多,就是因为学习资源中想当然的地方太多了。 概念 卷积神经网络…

WPF- vs中的WPF应用项目模板 如何自己实现

读书笔记 1. 单个 c#文件的 空白window应用程序 (只展示了一个button按钮) 2.C#文件 和xml文件 的空白window程序 .xml文件作为程序的资源 (只一个button按钮) 3. xmal和c#共同编译 形如使用VS 创建WPF应用项目模板 1.新建一个wpf空白项目 ,添加一个主c#文件 和xaml文件(属…

list底层详解

目录 介绍 list的实现 1.自定义节点 2.迭代器封装 构造函数 前置和后置 前置--和后置-- *操作符和->操作符 和!操作符 iterator和const_iterator 3. list类 构造函数和析构函数 赋值操作 头尾迭代器 插入和删除 头插头删尾插尾删 list接口函数总代码 介绍…

【开端】Java中最常用的一个类型String的使用

一、绪论 Java中最常用的一个类型是String,其实从JDK1.0 到JDK20 Java 开发工具包其实也经过很多演变,很多功能做了一些优化。这一节就把String类里的方法拎出来看看哪些是常用的,哪些经常用不到得到,哪些是已经有的,…

BaseCTF [第 2 周] lk

前言:做题笔记。 下载解压查壳。 64IDA打开。 查找字符串去。 跟进BaseCTF{ 找到 main 头部: 尾部: 程序: 选择题,咳,动漫迷可以做,也能得flag。(我不怎么看动漫。。) 告知我们,输…

【开发笔记】Notepad++配置

Notepad配置 Notepad保护色配置 settings --> Style Configurator 选择 Enable olobal foreground colourEnable global background colour 设置背景色 点击 Save & Close按钮,完成保存。 设置 Unix换行符

计算机网络 TCPUDP、IP、ARPRARP、NAT总结

文章目录 TCP 和 UDPUDPTCPTCP 三次握手半连接队列(SYN队列)全连接队列(Accept队列)TCP四次挥手为什么四次挥手为什么需要TIME_WAIT状态TIME_WAIT的危害为什么是2MSL 重传机制滑动窗口流量控制拥塞控制 IPIP地址分类A、B、C类地址…

javaee、ssm(maven)、springboot(maven)项目目录结构以及编译后文件目录存放路径

javaee项目目录结构: src下的文件或者是源码编译后都会放在WebRoot(项目根目录)文件夹\WebRoot\WEB-INF\classes目录中。 编译后的文件夹目录如下: 以上为普通的javaee项目目录结构,同maven工程目录结构是不一样的。…

Segment Anything:如何导出完整的ONNX模型?

在本文中,我将讨论 Segment Anything - 例如分割的神经网络,可用于从图像中分割任何对象而无需知道其类型。但是,这不是关于如何使用它的教程,因为它已经在官方存储库和其他类似文章中进行了描述。在这里,我将解释如何…

《计算机网络期末复习知识点大全》

目录 一、第一章 概述 1. TCP/IP分层网络体系结构、分层原因、作用 2. 时延、发送时延、传播时延 2.1 速率相关性能指标 2.1.1 速率 2.1.2 带宽 2.2 时间相关性能指标 2.2.1 发送时延 2.2.2 传播时延 2.3 考点例题 二、第二章 物理层 1. 编码与调制 2. 常用编码方…

人眼检测(单张图像-原始版)

目录 实验原理 实验代码 运行结果 改进代码 实验原理 要在C中使用OpenCV来检测图像中的人眼,你需要完成以下步骤: 安装OpenCV库并设置好开发环境。加载预训练的级联分类器(通常是用于人脸和眼睛检测的XML文件)。读取图像或视…

SQL-函数ing

1、字符串函数 # 字符函数 select concat(hello , mysql!); select lower(HELLO); select upper(hello); select lpad(01,5,-);# 左填充 select rpad(01,5,-);# 右填充 select trim( hello mysql ! );# 去除前后空格 select substring(hello mysql!,1,7);# 截取一部分字符前7…

【Java设计模式】非循环访问者模式:简化对象交互

文章目录 【Java设计模式】非循环访问者模式:简化对象交互一、概述二、非循环访问者设计模式的意图三、非循环访问者模式的详细解释及实际示例四、Java中非循环访问者模式的编程示例五、非循环访问者模式类图六、Java中何时使用非循环访问者模式八、非循环访问者模式…

XTuner微调个人小助手认知 #书生浦语大模型实战营#

1.任务: 本次的任务是使用 XTuner 微调 InternLM2-Chat-1.8B 实现自己的小助手认知,从而让模型能够个性化的回复,让模型知道他是我们的小助手,在实战营帮我们完成XTuner微调个人小助手认知的任务。并截图打卡。 任务打卡&#x…

深入探索【Hadoop】生态系统:Hive、Pig、HBase及更多关键组件(下)

🐇明明跟你说过:个人主页 🏅个人专栏:《大数据前沿:技术与应用并进》🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、什么是Hadoop 2、Hadoop生态系统的构成概览 二…

【html+css 绚丽Loading】 000019 五行轮回剑

前言:哈喽,大家好,今天给大家分享htmlcss 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 &#x1f495…

【云原生】Mysql 集群技术

PS:MySQL的源码编译进行实验环境操作 1、MySQL安装及初始化 (1)生成启动脚本 (2) 修改环境变量 (3)生成配置文件 (4)数据库初始化建立mysql基本数据 (5&…

UnrealEngine学习(03):虚幻引擎术语

1. 项目 虚幻引擎5项目(Unreal Engine 5 Project) 中包含游戏的所有内容。项目中包含的大量文件夹都在磁盘上,例如 Blueprints 和 Materials 。你可以按照自己的意愿命名文件夹并将其整理到项目中。虚幻编辑器(Unreal Editor&…