尽管可以通过不同的方式组合IO流类,但我们可能也就只用到其中的几种组合。下面的例子可以作为典型的IO用法的基本参考。在这些示例中,异常处理都被简化为将异常传递给控制台,但是这只有在小型示例和工具中才适用。在代码中,你需要考虑更加复杂的错误处理方式。

  同样,本文会包括如下几个方面:

  缓冲输入文件

  从内存输入

  格式化的内存输入

  基本的文件输出

  存储和恢复数据

  读写随机访问文件

  实用工具

  总结

1. 缓冲输入文件

  如果想要打开一个文件用于字符输入,可以使用以String或File对象作为文件名的FileReader。为了提高速度,我们可以对那个文件进行缓冲,那么我们需要将所产生的引用传给一个BufferedReader构造器。通过使用其readLine()方法来逐行读取文件,当readLine()返回null时,就到了文件末尾。

public class BufferedInputFile {public static String read(String fileName) throws Exception {BufferedReader br = new BufferedReader(new FileReader(fileName));StringBuilder str = new StringBuilder();String temp = null;while((temp = br.readLine()) != null) {str.append(temp + "\n");}br.close();return str.toString();}public static void main(String[] args) {try {System.out.println(BufferedInputFile.read("pom.xml"));}catch(Exception e) {e.printStackTrace();}}
}

  文件的全部内容都累积在字符串str中,最后记得调用close()来关闭流。

2. 从内存输入

  在下面的示例中,从上面的BufferedInputFile.read()读入的String结果被用来创建一个StringReader。然后调用read()每次读取一个字符,并把它打印到控制台。

public class MemoryInput {public static void main(String[] args) {try {StringReader sr = new StringReader(BufferedInputFile.read("pom.xml"));int c;while((c = sr.read()) != -1) {System.out.print((char)c);}}catch(Exception e) {}}}

  需要注意的是read()是以int形式返回下一个字节,因此必须将类型强转为char才能显示正确结果。

3. 格式化的内存输入

  要读取格式化数据,可以使用DataInputStream,它是一个面向字节的I/O类,我们可以用InputStream以字节的形式读取任何数据。

public class FormattedMemoryInput {public static void main(String[] args) {try {DataInputStream di = new DataInputStream(new ByteArrayInputStream(BufferedInputFile.read("pom.xml").getBytes()));while(di.available() != 0) {System.out.print((char)di.readByte());}}catch (Exception e) {e.printStackTrace();}}
}

  这里需要注意必须为ByteArrayInputStream的构造函数提供字节数组,而ByteArrayInputStream传递给DataInputStream之后进行了一次“装饰”,可以进行格式化输入(比如直接读取int、double等类型),这里我们只是通过readByte读取单个字节,调用该方法时任何字节的值都是合法的结果,因此返回值是不能用来检测输入是否结束,这里我们使用available()方法查看还有多少可供存取的字符来判断是否结束。

4. 基本的文件输出

  FileWriter对象可以向文件写入数据,通常会用BufferedWriter将其包装起来用以缓冲输出以提高性能。在本例中为了提供格式化机制,将其装饰成PrintWriter:

public class BasicFileOutput {static String file = "BasicFileOutput.out";public static void main(String[] args) {try {BufferedReader in = new BufferedReader(new StringReader(BufferedInputFile.read("pom.xml")));PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));String temp;int count = 0;while((temp = in.readLine()) != null) {out.println(count++ + temp);}in.close();out.close();System.out.println(BufferedInputFile.read(file));}catch(Exception e) {e.printStackTrace();}        }}

  这里在读取BasicFileOutput.out的内容之前,先调用了out的close()将其关闭,一方面是因为流用完之后需要及时关闭以节省资源,另一方面这里用到了缓冲区,如果不为所有的输出文件调用close(),缓冲区的内容可能不会刷新清空,这样可能导致信息不完整。

  另外Java SE5在PrintWriter中添加了一个辅助构造器,可以很方便根据文件名直接构造一个PrintWriter而不用执行一系列的装饰工作:

PrintWriter out = new PrintWriter(file);

5. 存储和恢复数据

  PrintWriter可以对数据进行格式化,以便阅读。但是为了输出可供另一个“流”恢复的数据,我们需要用DataOutputStream写入数据,并用DataInputStream恢复数据。当然,这些流可以是任何形式,在下面的例子中使用的是一个文件。

public class StoringAndRecoveringData {public static void main(String[] args) {try {DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.txt")));out.writeDouble(3.14159);out.writeUTF("That was pi");out.writeDouble(1.41413);out.writeUTF("Square root of 2");out.close();DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("data.txt")));System.out.println(in.readDouble());System.out.println(in.readUTF());System.out.println(in.readDouble());System.out.println(in.readUTF());in.close();}catch(Exception e) {e.printStackTrace();}}}

  使用DataOutputStream写入数据,Java可以保证我们可以使用DataInputStream准确地读取数据--无论读和写数据的平台多么不同。当我们使用DataOutputStream时,写字符串并且让DataInputStream能够恢复它的唯一可靠的做法就是使用UTF-8编码,在这个例子中是靠writeUTF()和readUTF()来实现的。

  writeDouble()和readDouble()方法能够写入和恢复double类型的数据。对于其他类型的数据,也有类似的方法用于读写。但是为了保证所有的读写方法都能够正常工作,我们必须知道流中数据项所在的确切位置,因为极有可能将保存的double数据作为一个简单的字节序列、char或其他类型读入。

6. 读写随机访问文件

  使用RandomAccessFile,类似于组合使用了DataInputStream和DataOutputStream,可以同时对一个文件执行读写操作,同时可以利用seek()在文件中到处移动,非常方便,关于RandomAccessFile的详细用法,前面有专门写过<<Java I/O系统:File和RandomAccessFile>>。

  但是在使用RandomAccessFile时,你需要知道文件的排版,这样才能正确地操作它,RandomAccessFile拥有读取基本类型和UTF-8字符串的各种具体方法。

public class UsingRandomAccessFile{static String file = "rtest.dat";static void display() throws IOException{RandomAccessFile rf = new RandomAccessFile(file,"r");for(int i = 0; i < 7; i++){System.out.println("Value " + i + ": " + rf.readDouble());}System.out.println(rf.readUTF());rf.close();}public static void main(String[] args) throws IOException{RandomAccessFile rf = new RandomAccessFile(file,"rw");for(int i = 0; i < 7; i++){rf.writeDouble(i*1.414);}rf.writeUTF("The end of the file");rf.close();display();rf = new RandomAccessFile(file,"rw");rf.seek(5*8);rf.writeDouble(47.0001);rf.close();display();}
}

  我们通过writeDouble()方法往文件中写入Double类型数据并通过readDouble()方法来读取,这就是我们需要直到排版的原因,如果读取的不是Double类型的数据有可能出现不是我们想要的结果。

7. 实用工具

  到这里我们学习了多种I/O流的典型用法,比如缓冲输入文件、从内存输入、基本的文件输出、存储和恢复数据、随机读写文件,这些都是Java I/O流比较典型的用法。这里我们发现读取文件、修改、在写出是一个很常见的程序化的任务,但是Java I/O类库的设计有一个问题,就是我们需要编写很多代码来实现这些操作,要记住如何打开文件是一件优点困难的事情。因此,下面是收集的一些帮助类,可以很容易为我们完成这些基本任务,记录在这里,方便以后查看。

  这里收集了两个工具:

  • 一个是TextFile,帮助我们读取和写入文件;
  • 另一个是BinaryFile,帮助我们简化二进制文件的读取。

7.1 读取文件

  TextFile类包含的static方法可以像简单字符串那样读写文本文件,并且我们可以创建一个TextFile对象,它用一个ArrayList来保存文件的若干行,好处是在我们操纵文件内容时可以使用ArrayList的所有功能。

public class TextFile extends ArrayList<String>{// 将文件读取到一行字符串中public static String read(String fileName){StringBuilder sb = new StringBuilder();try{BufferedReader in = new BufferedReader(new FileReader(new File(fileName).getAbsoluteFile()));try{String s;;while((s = in.readLine()) != null){sb.append(s).append("\n");}}finally{in.close();}}catch (IOException e){throw new RuntimeException(e);}return sb.toString();}// 单次调用将一个字符串写入一个文件public static void write(String fileName,String text){try{PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());try{out.print(text);}finally{out.close();}}catch(IOException e){throw new RuntimeException(e);}}// 读取文件,并通过正则表达式将其分离,保存在List中public TextFile(String fileName,String splitter){super(Arrays.asList(read(fileName).split(splitter)));// 因为split()方法有时会在返回的数组第一个位置产生一个空字符串if(get(0).equals(""))remove(0);}// 常规的分行读取public TextFile(String fileName){this(fileName,"\n");}// 将该TextFile中的内容分行写入指定文件中public void write(String fileName){try{PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());try{for(String item : this){out.println(item);}}finally{out.close();}}catch(IOException e){throw new RuntimeException(e);}}// 简单验证一下public static void main(String[] args){String file = read("TextFile.java");write("test.txt",file);TextFile text = new TextFile("test.txt");text.write("test2.txt");TreeSet<String> words = new TreeSet<String>(new TextFile("TextFile.java","\\W+"));System.out.println(words.headSet("a"));}
}

  这里利用静态的read()方法将文件读取到一个字符串中,再用静态的write()方法将其写入到文件中。然后将新写入的文件作为构造参数构造一个TestFile对象,利用其List的特性,将其内容写入文件test2中。这个类的作用是帮我们读取文件,可以通过静态的read方法读取到一个字符串中,也可以通过构造器读取文件到一个TextFile对象中。

7.2 读取二进制文件

public class BinaryFile{public static byte[] read(File bFile)throws IOException{BufferedInputStream bf = new BufferedInputStream(new FileInputStream());try{byte[] data = new byte[bf.available()];br.read(data);return data;}finally{bf.close();}}public static byte[] read(String bFile)throws IOException{return read(new File(bFile).getAbsoluteFile());}
}

8. 总结

  本文没有总结什么新的知识点,只是总结了一些Java I/O的常见用法比如缓冲输入文件、从内存输入、基本的文件输出、存储和恢复数据、随机读写文件等,并且搜集了两个工具类用来帮助我们读写文件读取二进制文件,以提高些代码的效率。

Java I/O系统学习系列三:I/O流的典型使用方式相关推荐

  1. Java I/O系统学习系列二:输入和输出

    编程语言的I/O类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象."流"屏蔽了实际的I/O设备中处理数据的细节. 在这个系列的第一篇 ...

  2. Java I/O系统学习系列一:File和RandomAccessFile

    I/O系统即输入/输出系统,对于一门程序语言来说,创建一个好的输入/输出系统并非易事.因为不仅存在各种I/O源端和想要与之通信的接收端(文件.控制台.网络链接等),而且还需要支持多种不同方式的通信(顺 ...

  3. Java高并发编程学习(三)java.util.concurrent包

    简介 我们已经学习了形成Java并发程序设计基础的底层构建块,但对于实际编程来说,应该尽可能远离底层结构.使用由并发处理的专业人士实现的较高层次的结构要方便得多.要安全得多.例如,对于许多线程问题,可 ...

  4. 数据库MYSQL学习系列三

    数据库MYSQL学习系列三 三.MYSQL事务与存储引擎 3.1-数据库事务 什么是事务 一系列有序的数据库操作: o要么全部成功 o要么全部回退到操作前的状态 o中间状态对其他连接不可见 事务的 ...

  5. idea学习系列三之版本管理工具

    idea学习系列三之版本管理工具 上一篇文章主要介绍了将idea中常用的快捷键,快捷键要想熟练那就得在实际的工作中多使用,刚开始可能很麻烦经常去笔记中找,不过用多了自然就熟练了. 这篇文件将会介绍一下 ...

  6. QT系统学习系列:1.2 PushButton(常规按钮)

    文章目录 一.PushButton 基础 PushButton介绍 给PushButton添加快捷键 PushButton构造函数 PushButton添加/更改(图标,文本,父类) PushButt ...

  7. Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream

    Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/ ...

  8. 零基础参加java培训的系统学习路线

    ​ 零基础想要学习java技术,那么最好的选择就是参加java培训,进行系统的学习,以下就是小编为大家整理的零基础参加java培训的系统学习路线,希望能够帮助到正在学习java技术的零基础同学. 零基 ...

  9. QT系统学习系列:1.2 ToolBar(工具栏)

    文章目录 ToolBar 基础 ToolBar介绍 movable 属性 allowedAreas 属性 orientation 属性 iconSize 属性 toolButtonStyle 属性 f ...

最新文章

  1. 计算机算法对程序设计的作用,计算机编程中数学算法的优化策略
  2. python3 元组 tuple 操作
  3. 分数换算小数补0法_分数怎么化成整数 分数转化方法
  4. 22行代码AC,三种解法——例题3-6_环状序列(UVa-1584)
  5. MTK 驱动(81)----不开机问题快速分析
  6. 【自我感悟致学弟学妹】大三上的感悟,何为真正优秀的人
  7. [我总结]8月第二周总结
  8. 机器学习ai选股_机器学习技术能够有效用于选股吗?(下)
  9. html盒子背景图,CSS盒子模型以及背景图
  10. 使用 conda uninstall xxx时,一直卡在 Collecting package metadata (repodata.json)
  11. 实例讲解kubernetes网络通信
  12. 使用TCP/IP协议栈指纹进行远程操作系统辨识
  13. windows/ubuntn 快捷键和命令行使用
  14. go语言的类型之间的相互转化和float保留小数时的四舍五入
  15. Amazon 邮箱大全
  16. MATLAB 输入和输出参数
  17. HTML开发 完美解决移动端H5页面pop弹出蒙版后底层滑动问题
  18. J - [永不止步-2017]_区间第K大-线段树维护
  19. android卡刷包自制rom之添加删除,添加/删除ROM内置APP的教程
  20. 区块链教程Fabric1.0源代码分析配置交易-生成通道配置二

热门文章

  1. hive表信息查询:查看表结构、表操作等--转
  2. Mysql数据库存储引擎--转
  3. 深入redis内部--初始化服务器
  4. 清除linux缓存命令
  5. 巨杉数据库 CTO 王涛:区块链+数据库,底层技术融合是否带来更大爆发?
  6. 回归、分类与聚类:三大方向剖解机器学习算法的优缺点
  7. 孙剑亲自撰文:我在 Face++ 的这半年
  8. 搜索业务增速下滑 Google廉颇老矣?
  9. 评分卡中的一些理论知识
  10. C语言文件读写(2)-文本文件写操作