平时写IO相关代码机会挺少的,但却都知道使用BufferedXXXX来读写效率高,没想到里面还有这么多陷阱,这两天突然被其中一个陷阱折腾一下:读一个文件,然后写到另外一个文件,前后两个文件居然不一样?解决这个问题之后,总结了几个注意点。

注意点一:Reader/Writer读写二进制文件是有问题的 :

上面代码使用BufferedReader一行一行地读取一个文件,然后使用BufferedWriter把读取到的数据写到另外一个文件中。如果文件是ASCCII形式的,则内容还是能够正确读取的。但如果文件是二进制的,则读写后的文件与读写前是有很大区别的。当然,把上面的readLine()换成read(char[])仍然不能正确读写二进制文件的。读写二进制文件请接着看下面注意点。

注意点二:read(byte[] b, int offset, int length)中的offset不是指全文件的全文,而是字节数组b的偏移量

现在已经知道使用Reader/Writer不能正确读取二进制文件,这是因为Reader/Writer是字符流,那就改用字节流ufferedInputStream/BufferedOutputStream,网上搜索到的例子大概是这样的:

每次读1024字节,然后写1024字节。这看似挺正确的,但实际写出来的文件与原文件是不同的。这样就怀疑可能是读写没有接上,因而把代码改成下面的形式:

这是误以为:先读一段,写一段,然后改变偏移量,然后使用新的偏移量再读一段、写一段,直到文件读写完毕。但这是错误的,因为使用BufferedXXX后,里面已经实现了这个过程。而read(byte[] b, int offset, int length)中的offset实际指的是把读到的数据存入到数组b时,从数组的哪个位置(即offset)开始放置数据;同理,write(byte[] b, int offset, int length)就是把b中的数据,从哪个位置(offset)开始写到文件中。

注意点三:使用 length=read (b, 0, 1024)读数据时,应该使用write(b, 0, length)来写

第二个注意点中的第一段代码的做法虽然在网上比较常见,但是有问题的。问题在哪呢?答案是:问题在byte[] b这个数组上。由于二进制文件使用比较工具时,只知道不同、但不能知道哪些不同(是否有更先进的比较工具?)。怎样确定它的不同呢?方法很简单:就把二进制文件改成文本文件就能看出结果了(Reader/Writer这种字符流虽然不能正确读写二进制文件,但InputStream/OutputStream这些字节流能既能正确读写二进制文件,也能正确读写文本文件)。由于使用了每次读1K(1024字节)的方式,所以会看到的结果是:写后的文件后面多出一段,这一段的长度与原文件大小以及b数组的大小有关。为了进一步确定是什么关系,把读的文件内容改为"1234567890123",而把b数组的大小改为10字节,这时结果就出来了:写后的文件内容变成"12345678901234567890",就是读了两遍。多出的内容的根源在这里:b数组的大小是10字节,而要读的内容长度是13字节,那就要读两次,第一次读了前10字节,此时b数组内的元素为前10个字符;再读第二次时,由于可读内容只有3个字符,那b数组的内容只有前3个字符被改变了,后面7个字符仍然保持上一次读取的内容。所以直接采用write(b)的方式,在第二次写文件时,内容就多写了一段不是第二次读取到的内容。

下面是正确的读写(即每次读了多少内容,写入的是多少内容,而不是写入整个数组):

注意点四:flush()和close()

flush()是把写缓冲区内的内容全部”吐“到文件上,如果没有它,就有可能很多内容还存在于写缓冲区内,而不是在文件中,也就是还有丢失的可能。

close()中会调用flush()。它是文件真正完成的标志,文件内容写完成后不关闭文件流,会导致一些”古怪“的问题。这个在网络中的流更能体现。

所以,写文件完成后注意关闭文件读写流。

161228、Java IO流读写文件的几个注意点的更多相关文章

  1. 161108、Java IO流读写文件的几个注意点

    平时写IO相关代码机会挺少的,但却都知道使用BufferedXXXX来读写效率高,没想到里面还有这么多陷阱,这两天突然被其中一个陷阱折腾一下:读一个文件,然后写到另外一个文件,前后两个文件居然不一样? ...

  2. Java IO流读写文件的几个注意点

     平时写IO相关代码机会挺少的,但却都知道使用BufferedXXXX来读写效率高,没想到里面还有这么多陷阱,这两天突然被其中一个陷阱折腾一下:读一个文件,然后写到另外一个文件,前后两个文件居然不 ...

  3. Java:IO流与文件基础

    Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...

  4. java io流 对文件夹的操作

    java io流 对文件夹的操作 检查文件夹是否存在 显示文件夹下面的文件 ....更多方法参考 http://www.cnblogs.com/phpyangbo/p/5965781.html ,与文 ...

  5. java io流 创建文件、写入数据、设置输出位置

    java io流 创建文件 写入数据 改变system.out.print的输出位置 //创建文件 //写入数据 //改变system.out.print的输出位置 import java.io.*; ...

  6. Java IO如何读写文件

    Java把这些不同来源和目标的数据都统一抽象为数据流:Java语言的输入输出功能是十分强大而灵活的:在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上 ...

  7. Java 字符流读写文件

    据说,java读写文件要写很多,贼麻烦,不像c艹,几行代码就搞定.只能抄抄模板拿来用了. 输入输出流分字节流和字符流.先看看字符流的操作,字节转化为字符也可读写. 一.写入文件 1.FileWrite ...

  8. IO流 读写文件

    读写文件 如前所述,一个流被定义为一个数据序列.输入流用于从源读取数据,输出流用于向目标写数据. 下图是一个描述输入流和输出流的类层次图. 下面将要讨论的两个重要的流是 FileInputStream ...

  9. java IO流 Zip文件操作

    一.简介 压缩流操作主要的三个类 ZipOutputStream.ZipFile.ZipInputStream ,经常可以看到各种压缩文件:zip.jar.GZ格式的压缩文件 二.ZipEntry   ...

随机推荐

  1. 2.线性表-Linked list

    fatal.h #include <stdio.h> #include <stdlib.h> #define Error( Str ) FatalError( Str ) #d ...

  2. Apache Spark技术实战之9 -- 日志级别修改

    摘要 在学习使用Spark的过程中,总是想对内部运行过程作深入的了解,其中DEBUG和TRACE级别的日志可以为我们提供详细和有用的信息,那么如何进行合理设置呢,不复杂但也绝不是将一个INFO换为TR ...

  3. java并发编程-基础

    线程带来的风险 安全性:多线程操作执行顺序的不可预测性 -- 永远不发生糟糕的事情: 活跃性:代码无法得到执行,死锁.饥饿问题 -- 某件正确的事情最终会发生: 性能问题:活跃性只意味着某件事最终会发 ...

  4. 关于datagridview里使用combox的总结

    最近写的程序中需要在DataGridView中使用下拉选择的功能,首选方案是列的ColumnType属性 使用EditingControlShowing事件, if (e.Control is Com ...

  5. [bzoj2463]谁能赢呢

    我们通过观察可以发现,当n为偶数时,一定可以转化为一种先手必胜态,即棋盘可以被骨牌所覆盖, 如果n是奇数,那么去掉一格后一定能被1*2的骨牌覆盖,但是先手从左上角走,就进入了这个S态(必胜态),那么和 ...

  6. 使用JSON.Net(Newtonsoft.Json)作为ASP.Net MVC的json序列化和反序列化工具

    ASP.Net MVC默认的JSON序列化使用的是微软自己的JavaScriptSerializer.性能低不说,最让人受不了的是Dictionary<,>和Hashtable类型居然对应 ...

  7. PHP 用 mb_strimwidth() 截取文章摘要

    按字符宽度获取 mb_strimwidth ( string $str , int $start , int $width [, string $trimmarker [, string $encod ...

  8. 《项目经验》--通过js获取前台数据向一般处理程序传递Json数据,并解析Json数据,将前台传来的Json数据写入数据库表中

      先看一下我要实现的功能界面:   这个界面的功能在图中已有展现,课程分配(教师教授哪门课程)在之前的页面中已做好.这个页面主要实现的是授课,即给老师教授的课程分配学生.此页面实现功能的步骤已在页面 ...

  9. target-densitydpi

    一个屏幕像素密度是由屏幕分辨率决定的,通常定义为每英寸点的数量(dpi).Android支持三种屏幕像素密度:低像素密度,中像素密度,高像素密度.一个低像素密度的屏幕每英寸上的像素点更少,而一个高像素 ...

  10. idea使用心得(4)-踩过的坑

    1.非法的表达式开始 / 需要';' / 未结束的字符串文字  表现形式:    原因/解决:       这个一定是文件编码问题:依次检查setting中的file Encodings 中的IDE ...