Java I/O系统 文件读写


Java I/O系统

1 Java I/O系统简介

Java类库的设计者通过创建大量的类来实现其强大的I/O系统,自从Java 1.0版本以来,Java的I/O类库发生了明显改变,在原来面向字节的类中添加了面向字符和基于Unicode的类,在JDK 1.4中,添加了nio类,添加进来是为了改进性能及功能。为了能够充分理解Java I/O系统以便正确地运用,我们需要学习相当数量的类。

1.1   File类

在介绍真正用于在流中读写数据的类之前,需要先介绍一个实用类库工具,它可以帮助我们处理文件目录问题。

File类这个名字有一定误导性,它不仅能够代表一个特定文件的名称,又能代表一个目录下一组文件的名称。

假设我们想查看一个目录列表,可以用两种方法来使用File对象。如果我们调用不带参数的list()方法,便可以获得此File对象包含的全部列表;如果我们想获得一个受限列表,例如,想得到所有扩展名为.java的文件,那么就要用到“目录过滤器”。

下面是一个简单的示例:


该示例通过list()参数的匿名内部类实现了FilenameFilter接口,请注意FilenameFilter的接口是多么简单:


         accept()方法必须接受一个代表某个特定文件所在目录的File对象,以及包含了那个文件名的一个String,list()方法会为此目录对象下的每个文件名调用accept(),来判断该文件是否包含在内;判断结果由accept()返回的布尔值表示。

         在示例方法中,accept()会使用一个正则表达式来匹配文件的名字,通过使用accept()会返回一个数组。

         1.2绝对路径和相对路径

        在上述getFileList()函数中,参数String filePath表示文件的路径,在java中,有绝对路径和相对路径两种表示方式。

         绝对路径是指书写文件的完整路径,例如d:\java\Hello.java,该路径中包含文件的完整路径d:\java以及文件的全名Hello.java。使用该路径可以唯一的找到一个文件,不会产生歧义。但是使用绝对路径在表示文件时,受到的限制很大,且不能在不同的操作系统下运行,因为不同操作系统下绝对路径的表达形式存在不同。

        相对路径是指书写文件的部分路径,例如\test\Hello.java,该路径中只包含文件的部分路径\test和文件的全名Hello.java,部分路径是指当前路径下的子路径,例如当前程序在d:\abc下运行,则该文件的完整路径就是d:\abc\test。使用这种形式,可以更加通用的代表文件的位置,使得文件路径产生一定的灵活性。

        在Eclipse项目中运行程序时,当前路径是项目的根目录,例如工作空间存储在d:\javaproject,当前项目名称是Test,则当前路径是:d:\javaproject\Test。在控制台下面运行程序时,当前路径是class文件所在的目录,如果class文件包含包名,则以该class文件最顶层的包名作为当前路径。

        另外在Java语言的代码内部书写文件路径时,需要注意大小写,大小写需要保持一致,路径中的文件夹名称区分大小写。由于’\’是Java语言中的特殊字符,所以在代码内部书写文件路径时,例如代表“c:\test\java\Hello.java”时,需要书写成“c:\\test\\java\\Hello.java”或“c:/test/java/Hello.java”,这些都需要在代码中注意。

         1.3读取文件

         将文件中的数据读入程序,是将程序外部的数据传入程序中,应该使用输入流InputStream或Reader。而由于读取的是特定的数据源(文件),则可以使用输入对应的子类FileInputStream或FileReader实现。

         在实际书写代码时,需要首先熟悉读取文件在程序中实现的过程。在Java语言的IO编程中,读取文件是分两个步骤:1、将文件中的数据转换为流,2、读取流内部的数据。其中第一个步骤由系统完成,只需要创建对应的流对象即可,对象创建完成以后步骤1就完成了,第二个步骤使用输入流对象中的read方法即可实现了。

        使用输入流进行编程时,代码一般分为3个部分:

l  创建流对象

l  读取流对象内部的数据

l  关闭流对象。

         具体流程如下图所示:


图 读取文件流程图

         当然,在读取文件时,也可以使用Reader类的子类FileReader进行实现,在编写代码时,只需要将上面示例代码中的byte数组替换成char数组即可。

         使用FileReader读取文件时,是按照char为单位进行读取的,所以更适合于文本文件的读取,而对于二进制文件或自定义格式的文件来说,还是使用FileInputStream进行读取,方便对于读取到的数据进行解析和操作。

         读取其它数据源的操作和读取文件类似,最大的区别在于建立流对象时选择的类不同,而流对象一旦建立,则基本的读取方法是一样,如果只使用最基本的read方法进行读取,则使用基本上是一致的。这也是IO类设计的初衷,使得对于流对象的操作保持一致,简化IO类使用的难度。

         1.4输出文件

         基本的输出流包含OutputStream和Writer两个,区别是OutputStream体系中的类(也就是OutputStream的子类)是按照字节写入的,而Writer体系中的类(也就是Writer的子类)是按照字符写入的。

        使用输出流进行编程的步骤是:

l  建立输出流:建立对应的输出流对象,也就是完成由流对象到外部数据源之间的转换。

l  向流中写入数据:将需要输出的数据,调用对应的write方法写入到流对象中。

l  关闭输出流:在写入完毕以后,调用流对象的close方法关闭输出流,释放资源。

        在使用输出流向外部输出数据时,程序员只需要将数据写入流对象即可,底层的API实现将流对象中的内容写入外部数据源,这个写入的过程对于程序员来说是透明的,不需要专门书写代码实现。

        在向文件中输出数据,也就是写文件时,使用对应的文件输出流,包括FileOutputStream和FileWriter两个类,下面以FileOutputStream为例子说明输出流的使用。


图 输出文件流程图

         在实际写入文件时,有两种写入文件的方式:覆盖和追加。其中“覆盖”是指清除原文件的内容,写入新的内容,默认采用该种形式写文件,“追加”是指在已有文件的末尾写入内容,保留原来的文件内容,例如写日志文件时,一般采用追加。在实际使用时可以根据需要采用适合的形式,可以使用:

         public FileOutputStream(String name,boolean append)

         只需要使用该构造方法在构造FileOutputStream对象时,将第二个参数append的值设置为true即可。

           其实,所有的数据文件,包括图片文件、声音文件等等,都是以一定的数据格式存储数据的,在保存该文件时,将需要保存的数据按照该文件的数据格式依次写入即可,而在打开该文件时,将读取到的数据按照该文件的格式解析成对应的逻辑即可。

        最后,在数据写入到流内部以后,如果需要立即将写入流内部的数据强制输出到外部的数据源,则可以使用流对象的flush方法实现。如果不需要强制输出,则只需要在写入结束以后,关闭流对象即可。在关闭流对象时,系统首先将流中未输出到数据源中的数据强制输出,然后再释放该流对象占用的内存空间。

        使用FileWriter写入文件时,步骤和创建流对象的操作都和该示例代码一致,只是在转换数据时,需要将写入的数据转换为char数组,对于字符串来说,可以使用String中的toCharArray方法实现转换,然后按照文件格式写入数据即可。

        对于其它类型的字节输出流/字符输出流来说,只是在逻辑上连接不同的数据源,在创建对象的代码上会存在一定的不同,但是一旦流对象创建完成以后,基本的写入方法都是write方法,也需要首先将需要写入的数据按照一定的格式转换为对应的byte数组/char数组,然后依次写入即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值