java 文件缓冲区_Java开发笔记(八十六)通过缓冲区读写文件

前面介绍了利用文件写入器和文件读取器来读写文件,因为FileWriter与FileReader读写的数据以字符为单位,所以这种读写文件的方式被称作“字符流I/O”,其中字母I代表输入Input,字母O代表输出Output。可是FileWriter的读操作并不高效,缘由在于FileWriter每次调用write方法都会直接写入文件,假如某项业务需要多次调用write方法,那么程序就会写入文件同样次数。因为写文件本质是写磁盘,磁盘的速度远不如内存,所以频繁地写文件必然严重降低程序的运行效率。为此Java又设计了缓存写入器BufferedWriter,它的write方法并不直接写入文件,而是先写入一块缓存,等到缓存写满了再将缓存上的数据写入文件。由于缓存空间位于内存之中,写入缓存等同访问内存,这样相当于把写磁盘动作替换成写内存动作,因此BufferedWriter的整体写文件性能要大大优于FileWriter。除此之外,BufferedWriter还新增了下列几个方法:

newLine:往文件末尾添加换行标记(Window系统是回车加换行)。当然实际上是先往缓存添加换行标记,并非直接往磁盘写入换行标记。

flush:立即将缓冲区中的数据写入磁盘。默认情况要等缓冲区满了才会写入磁盘,或者调用close方法关闭文件之时也会写入磁盘,但是有时程序猴急,一定要立即写入磁盘,此时就需调用flush方法强行写磁盘。

使用缓存写入器之前要先创建文件读取器对象,并获得父类Writer的实例,然后再据此创建缓存写入器对象。下面是通过缓存写入器把多行字符串写入文件的代码例子:

private static String mSrcName = "D:/test/aad.txt";

// 使用缓存字符流写入文件

private static void writeBuffer() {

String str1 = "白日依山尽,黄河入海流。";

String str2 = "欲穷千里目,更上一层楼。";

File file = new File(mSrcName); // 创建一个指定路径的文件对象

// try(...)允许在圆括号内部拥有多个资源创建语句,语句之间以冒号分隔

// 先创建文件写入器,再根据文件读取器创建缓存写入器

try (Writer writer = new FileWriter(file);

BufferedWriter bwriter = new BufferedWriter(writer);) {

// FileWriter的每次write调用都会直接写入磁盘,不但效率低,性能也差。

// BufferedWriter的每次write调用会先写入缓冲区,直到缓冲区满了才写入磁盘,

// 缓冲区大小默认是8K,查看源码defaultCharBufferSize = 8192;

// 资源释放的close方法再把缓冲区的剩余数据写入磁盘,

// 或者中途调用flush方法也可提前将缓冲区的数据写入磁盘。

bwriter.write(str1); // 往文件写入字符串

bwriter.newLine(); // 另起一行,也就是在文件末尾添加换行标记(Window系统是回车加换行)

bwriter.write(str2); // 往文件写入字符串

//bwriter.flush(); // 把缓冲区中的数据写入磁盘

} catch (Exception e) {

e.printStackTrace();

}

}

既然文件写入器有对应的缓存写入器,那么文件读取器也有对应的缓存读取器BufferedReader。BufferedReader的实现原理与它的兄弟BufferedWriter类似,另外BufferedReader比起文件读取器新增了如下方法:

readLine:从文件中读取一行数据。

mark:在当前位置做个标记。

reset:重置文件指针,令其回到上次标记的位置。也就是回到上次mark方法标记的文件位置。

lines:读取文件内容的所有行,返回的是Stream流对象,之后便可按照流式处理来加工该字符串流。

若想使用缓存读取器,依然要先创建文件读取器,再根据其父类的读取器实例创建缓存读取器。下面是通过缓存读取器从文件中读取多行字符串的代码例子:

// 使用缓存字符流读取文件

private static void readBuffer() {

File file = new File(mSrcName); // 创建一个指定路径的文件对象

// try(...)允许在圆括号内部拥有多个资源创建语句,语句之间以冒号分隔

// 先创建文件读取器,再根据文件读取器创建缓存读取器

try (Reader reader = new FileReader(file);

BufferedReader breader = new BufferedReader(reader);) {

breader.mark((int) file.length()); // 做个标记

for (int i=1; ; i++) {

// FileReader只能一个字符一个字符地读,或者一次性读进字符数组。

// BufferedReader还支持一行一行地读。

String line = breader.readLine(); // 从文件中读出一行文字

if (line == null) { // 读到了空指针,表示已经到了文件末尾

break;

}

System.out.println("第"+i+"行的文字为:"+line);

}

breader.reset(); // 重置文件指针,令其回到上次标记的位置

for (int i=1; ; i++) {

String line = breader.readLine(); // 从文件中读出一行文字

if (line == null) { // 读到了空指针,表示已经到了文件末尾

break;

}

System.out.println("又读了一遍 第"+i+"行的文字为:"+line);

}

//breader.lines(); // 返回Stream对象,之后可按照流式处理来加工该字符串流

} catch (Exception e) {

e.printStackTrace();

}

}

注意到以上代码BufferedWriter和BufferedReader的创建语句都位于try后面的圆括号之中,这是因为Writer与Reader两大家族统统实现了AutoCloseable接口,所以由它们繁衍而来的所有子类都具备自动释放资源的功能。另外,try语句支持同时管理多个资源类,只要它们的对象创建语句以冒号隔开,程序在运行时即可自动回收相关的资源。

结合运用读操作和写操作,可以实现文件复制的功能,无非是一边从源文件中读出数据,另一边紧接着往目标文件写入数据。采用缓存读取器和缓存写入器逐行复制的话,具体的文件复制代码示例如下:

private static String mSrcName = "D:/test/aad.txt";

private static String mDestName = "D:/test/aad_copy.txt";

// 通过缓存字符流逐行复制文件

private static void copyFile() {

File src = new File(mSrcName); // 创建一个指定路径的源文件对象

File dest = new File(mDestName); // 创建一个指定路径的目标文件对象

// try(...)允许在圆括号内部拥有多个资源创建语句,语句之间以冒号分隔

// 分别创建源文件的缓存读取器,以及目标文件的缓存写入器

try (BufferedReader breader = new BufferedReader(new FileReader(src));

BufferedWriter bwriter = new BufferedWriter(new FileWriter(dest));) {

for (int i=0; ; i++) {

String line = breader.readLine(); // 从文件中读出一行文字

if (line == null) { // 读到了空指针,表示已经到了文件末尾

break;

}

if (i != 0) { // 第一行开头不用换行

bwriter.newLine(); // 另起一行,也就是在文件末尾添加换行标记

}

bwriter.write(line); // 往文件写入字符串

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("文件复制完成,源文件大小="+src.length()+",新文件大小="+dest.length());

}

或者也可逐个字符来复制文件,此时BufferedReader每次调用的read方法只返回整型数表示一个字符,并且BufferedWriter每次调用的write方法也只写入该字符对应的整型数。通过依次遍历源文件的所有字符,同时往目标文件依次写入这些字符,从而完成逐个字符复制文件的操作流程。下面是采取逐字符复制文件的代码例子:

// 通过缓存字符流逐个字符复制文件

private static void copyFileByInt() {

File src = new File(mSrcName); // 创建一个指定路径的源文件对象

File dest = new File(mDestName); // 创建一个指定路径的目标文件对象

// try(...)允许在圆括号内部拥有多个资源创建语句,语句之间以冒号分隔

// 分别创建源文件的缓存读取器,以及目标文件的缓存写入器

try (BufferedReader breader = new BufferedReader(new FileReader(src));

BufferedWriter bwriter = new BufferedWriter(new FileWriter(dest));) {

while (true) { // 开始遍历文件中的所有字符

int temp = breader.read(); // 从源文件中读出一个字符

if (temp == -1) { // read方法返回-1表示已经读到了文件末尾

break;

}

bwriter.write(temp); // 往目标文件写入一个字符

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("文件复制完成,源文件大小="+src.length()+",新文件大小="+dest.length());

}

需要注意的是,使用字符流复制文件只有逐行复制和逐字符复制两种方式,不可采取整个读到字符数组再整个写入字符数组的方式。之所以不能通过字符数组复制文件,是因为中文跟英文不一样,一个汉字会占用多个字节(GBK编码的每个汉字占用两个字节,UTF8编码的每个汉字占用三个字节)。若要把文件内容读到字符数组,势必先得知晓该数组的长度,可是调用文件对象的length方法只能得到该文件的字节长度,并非字符长度。譬如“白日依山尽”这个字符串在内存中的字符数组长度为5,写到UTF8编码的文件之后,文件大小是5*3=15字节;接着想把文件内容读到字符数组,然而15字节的文件天晓得它有几个字符,可能有5个UTF8编码的中文字符,也可能有15个英文字符,也可能有5个GBK编码的中文字符加5个英文字符共10个字符,总之你根本想不到该分配多大的字符数组。既然确定不了待读取的字符数组长度,就无法一字不差地复制文件内容了。

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

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

相关文章

Scramble String -- LeetCode

原题链接: http://oj.leetcode.com/problems/scramble-string/这道题看起来是比較复杂的,假设用brute force,每次做分割,然后递归求解,是一个非多项式的复杂度,一般来说这不是面试官想要的答案。这事实上是一道三维动态…

xuggler实现视频压缩_Xuggler视频处理简介

xuggler实现视频压缩注意:这是我们的“ Xuggler开发教程 ”系列的一部分。 随着Internet中视频的爆炸性增长,开发人员经常需要在其应用程序中操纵视频内容。 Xuggler是Java开发人员的免费开放源代码库,可用于实时解压缩,处理和压缩…

oledb excel java_C#中Excel 2016的oledb连接字符串

通过Office 365程序从本地安装的Office 13升级到Office 16后,我发生了这种情况 . 我得到了这个例外:Microsoft.ACE.OLEDB.12.0提供程序未在本地计算机上注册 .我无法通过Office 365安装过程找到安装驱动程序的方法 .我在App.config中的连接字符串使用它的…

位,字,字节之间关系及关联知识普及

1》 位、字、字节关系8位(bit)1字节(Byte),1024字节1KB;提到了字节,不得不再提到“字”这个计量单位:“字”由若干个字节构成,字的位数叫做字长,字长就是说字所对应的二进制数的长度…

Android 绘制动态图

最近准备技能大赛,需要将从传感器中读出的数据在移动客户端以图的形式绘制出来,因为平时很少绘图,于是各种查资料,算是勉强做出来了。 以下是大赛理论效果图(左)和实际效果图(右)&am…

海外 谷歌 app api_Google App Engine Java功能和命名空间API

海外 谷歌 app api功能API 使用Capabilities API,您的应用程序可以检测特定API功能的停机和计划停机时间。 您可以使用此API来检测应用程序何时不可用,然后绕过它来减少应用程序的停机时间。 我们该如何处理呢? 1.优雅:创建一个…

$(document).ready() 和 window.onload 方法比较

说明 页面加载文档完毕后,浏览器会通过 Javascript 为 DOM 元素添加事件。 Javascript 使用 window.onload 方法,而 jQuery 使用 $(document).ready() 方法。 $(document).ready() 方法可以极大的提高 Web 应用程序的相应速度,因为该方法可以…

python在excel中查找内容_用python实现excel中查找指定字符的行信息

标签:print python实现 run div col with open value row 信息用python实现excel中查找指定字符的行信息strr # 字符串 or 字符filename # 文件名路径with open(filename,‘r‘) as fp:for line in fp:if strr in line:print (line.rows)将会输出ex…

使用活动记录执行CRUD

本文是我们学院课程的一部分,标题为jOOQ –类型安全的数据库查询 。 在SQL和特定关系数据库很重要的Java应用程序中,jOOQ是一个不错的选择。 当JPA / Hibernate抽象过多,JDBC过多时,这是一种替代方法。 它显示了一种现代的领域特…

java undo_用JAVA实现Undo、Redo,Copy、Paste、Cut_java

programlover原作package clipborad;import javax.swing.JTextArea;import java.awt.datatransfer.*;import java.awt.*;import javax.swing.*;import java.io.*;import javax.swing.undo.*;http://www.gaodaima.com/64851.html用JAVA实现Undo、Redo,Copy、Paste、Cut_javaimpo…

项目管理控件Project Management Library

Project Management Library是一款项目管理控件,包含了项目管理相关的Windows客户端控件,如:ProjectView, ResourcesView, ScheduleView, StatisticsView。支持所有.NET语言,可以用于Windows桌面应用程序,具有标准的界面和操作自定义设置、拖…

maven aspectj_使用Spring AspectJ和Maven进行面向方面的编程

maven aspectjSpring框架附带AOP支持。 实际上,如Spring参考文档中所述 , “ Spring的关键组件之一是AOP框架。 尽管Spring IoC容器不依赖于AOP,这意味着您不需要使用AOP,但AOP是对Spring IoC的补充,以提供一种功能强…

ios 查询mysql数据库操作系统_iOS数据库FMDB--增删改查(模糊查询)详细介绍

简介:很早就想整理一下数据库的使用了,刚好最近接触较多,加之可以安排出空余的时间,所以瓜子我贡献出自己喝咖啡的时间整理一下FMDB的使用,以下是对FMDB的介绍以及基本使用 --- insert、delete、update、select。其中s…

java arraylist 重复_Java中ArrayList去除重复元素

Java中ArrayList去除重复元素//删除ArrayList中重复元素public static void removeDuplicate(ArrayList list) {for ( int i 0 ; i for ( int j list.size() - 1 ; j > i; j -- ) {ForCytoLevel3 jjj (ForCytoLevel3)list.get(j);ForCytoLevel3 i…

c#时间转换

转自 http://blog.csdn.net/yysyangyangyangshan/article/details/6782874最近做ASP.NET的一个项目,获取时间的时候,由于我的系统时间设置了上午和下午,结果DateTime.Now老是写不到数据库中,然后,上网查了个[csharp]vi…

SQL Server 2008 R2如何生成带数据的数据库脚本

1.对想要复制的数据库右键,“任务”,“生成脚本” 2.下面需要注意的是,默认情况下,只会生成仅架构的脚本,也就是说仅仅有表结构,而没有数据的空壳。所以需要额外的设置。 在设置脚本编写选项,选…

java saxreader_JAVA解析XML,SAXReader无法使用

写了段代码要解析XML文件。for (int p 0; p < files.length; p) {System.out.println("Dom4jxml2:333::"p);if (files[p].isFile() && files[p].getName().startsWith("CN_MT1101_")) {File f new File(files[p].getPath());System.out.print…

methodhandle_概览Java 7 MethodHandle及其用法

methodhandle由于Java的Reflection API&#xff0c;我们已经能够在运行时检查和更改程序执行。 特别是&#xff0c;我们可以在运行时观察接口/类/方法和字段&#xff0c;而无需在编译时知道它们的名称。 JDK 7为这种动态/运行时检查引入了一个新的参与者&#xff0c;即方法句柄…

quartz CronExpression表达式

一个cron表达式有至少6个&#xff08;也可能7个&#xff09;有空格分隔的时间元素。按顺序依次为1.秒&#xff08;0~59&#xff09;2.分钟&#xff08;0~59&#xff09;3.小时&#xff08;0~23&#xff09;4.天&#xff08;月&#xff09;&#xff08;0~31&#xff0c;但是你需…

java两个字符串前缀_java – 找到两个字符串的最长公共前缀

我想找到两个字符串的最长公共前缀.有没有办法循环我的最后几个if语句,以便我可以结束彼此不匹配的最后几个字符&#xff1f;System.out.println("Enter the first string: ");String s input.nextLine();System.out.println("Enter the second string: "…