§ 1.3 文件存取
内容提要
计算机用文件来长期保存大量的数据, 即使在创建这些数据
的程序终止之后, 这些数据仍将保留在计算机中 。 文件的
应用是如此的广泛, 因此, 文件处理是任何一种编程语言
所必备的一项重要功能 。 常见的文件操作包括打开文件,
读文件, 写文件, 关闭文件等 。 本节讲述了如何操作文件,
主要内容如下,
? 数据层次结构
? 顺序文件和随机存取文件
? 文件操作:打开 /关闭, 读 /写, 更新
§ 1.3 文件存取
任务
HNS软件学院开发部在对图书馆管理系统进行系统分析和
概要设计后, 进入到系统实现阶段 。 根据现阶段的业务需
求, 要求以文件的方式存取图书馆用户的基本信息, 因此,
要求您编写程序完成以下的任务,
1,将用户的基本信息存储到文件中;
2,从文件获得用户的基本信息;
3,更新文件中用户的基本信息
1.3.1 数据层次结构
数值 0和 1是计算机中最小的数据项, 这样的数据项称为位 (Bit)。 计算
机中真正可以处理的只是由, 0”,,1”组成的二进制数据, 但这种数据
易出错且不易记忆 。 因此, 相对于 0,1数据, 程序员更愿意操作具有一
定格式的数据, 如数字 (0~9),字母 (a~z和 A~Z),特殊符号 (!,@,#,$、
%等 )。 这些数字, 字母和特殊符号统称为字符 (Character)。 计算机的
字符集是所有用于编写程序和表示数据项的字符的集合, 字符集中的所
有字符都可转换成一个二进制数 。 Java中的字符是 Unicode字符, 占据
两个字节, 每个字节包含 8位 (0或 1)。
正如字符是由位构成的, 而字段 (Field)是由字符构成 。 一个字段是一
组用于传递信息的字符 。 例如, 一串字母可以用来表示一个人的英文名
字 。 一组相关的字段构成一个记录 (Record),例如, 在图书管理系统中,某个用户的记录可能由以下字段构成,
? 姓名
? ID号
? 用户类别
? 基本信息
1.3.1 数据层次结构
在上面的例子中, 每个字段都属于同一个图书管理系统的用户 。 当然,
一个图书管理系统肯定有多个用户, 因此每个用户都有一条用户记录 。这些用户记录可以放置到一个用户文件中 。 一个文件 (File)由一组相关
的记录组成 。 下图显示了这种数据层次关系 。
位
字节 ( ASCII 字符集的 J 字符 )
字段
记录
文件
1.3.1 数据层次结构
为了方便从文件中获取特定的记录, 每条记录至少应该选
择一个字段作为记录键 (Record Key)。 在所有的记录中, 记
录键的值是唯一的, 所以, 一个记录的记录键将这条记录
和其它记录区分开来 。 记录键一般用于对记录进行查找和
排序 。 在前面描述的用户记录中, ID号可作为记录键, 用
户的名字可能有重复, 但其 ID号肯定是唯一的 。
1.3.1 数据层次结构
注意, Java没有对文件的结构做出强制规定, 因此, 在物
理层次上, Java文件也就不存在诸如字段, 记录这样的概念 。
实际上, 对操作系统而言, 文件就是字节的集合 。 因
此, Java程序员必须将文件结构化, 才能在逻辑上实现文
件的记录存储结构 。 也就是说, 如果程序员想把一组记录
存储在文件中, 必须将这组记录按照一定的数据格式写入
到文件中, 当以后想使用这组记录的时候, 再以相同的数
据格式从文件中读出 。 如果记录的写入格式和读出格式不
一样, 则从文件中读出的数据将是一堆乱码 。
1.3.2 顺序文件和随机存取文件
前面讲到的文件读写都是按照顺序进行的, 即从文件开头按
顺序一直读 /写到文件的末尾 。 如果一个程序想从文件的中
间开始读 /写数据, 或是想从文件中的指定位置开始读 /写
数据, 该如何处理呢? 在 Java 中定义了一个
RandomAccessFile类 (随机存取文件类 ),它提供了随机访
问文件的方法 。
RandomAccessFile类之所以能随机访问文件, 是由于它定
义了一个文件指针 (File Pointer),该指针指向文件的当
前读 /取位置 。 通过移动这个指针, 就可以从文件的任何位
置进行读 /写操作 。
1.3.2 顺序文件和随机存取文件
RandomAccessFile类可以通过下面的构造方法来构造,
RandomAccessFile(File file,String mode)
RandomAccessFile(String filename,String mode)
参数 mode指定文件的访问方式,, r”代表以只读的方式打开文件,, rw”
代表以读 /写的方式打开文件 。 假如文件不能被打开或是创建, 将抛出
FileNotFoundException。
和 File类一样, RandomAccessFile类也提供了 read()方法和 write()方
法来读 /写文件 。 除此之外, RandomAccessFile类还提供了 readInt()、
writeInt()等方法来读 /写原始类型数据 。
RandomAccessFile类最重要的方法是 seek()方法, 该方法定义如下,
void seek(long position) throws IOException
该方法用来设置文件指针的偏移量, 即设置文件的读 /写位置 。 参数
position是一个长整型数据, 指定从文件开始位置到读 /写位置的偏移
量 (以字节为计数单位 )。 如果 position的值小于等于 0,则抛出
IOException异常 。
1.3.2 顺序文件和随机存取文件
示例 1.3.1 使用 RandomAccessFile类编写一段代码实现如下功
能,
1,打开一个新文件, 依次写入数字 0~9(以整数形式保存 ),并
关闭该文件 。
2,再次打开该文件, 找到数字 7的存储位置, 将数字 7更新为
17,并关闭文件 。
任务解决
通过前面相关知识的学习, 使我们初步具备了解决任务的能力 。
分析,
在保存用户信息之前, 应该按照一定的数据格式组织用户信息, 然后再写
入到文件中, 否则文件中的用户信息将是杂乱无章的, 以后无法从文件
中读出正确的数据 。 前面我们已经讲述了文件在物理层次上只是字节的
集合, 因此, 必须将文件结构化, 才能在逻辑上实现文件的记录存储结
构 。 对于每一条用户信息, 我们都建立一条相应的记录来描述, 然后将
记录写入到文件中, 就实现了文件的结构化 。
在本章第二小节的任务解决中, 我们已经构造了一个可序列化的用户类
(UserRecord),该类有五个属性, 分别是 ID号, 姓名, 用户类别, 基本
信息和密码 。 我们通过实例化一个用户对象的方式来描述每一个实际的
图书馆用户, 可以将每一个用户对象看成是一条用户记录, 将对象的属
性看成是记录的字段 。
将包含了用户信息的用户对象写入到文件中, 就完成了, 将用户的基
本信息存储到文件中, 这个任务 。 将文件中的用户对象依次读出, 再从
对象中获得用户信息, 就完成了, 从文件获得用户的基本信息, 这个任
务 。
任务解决
在确定了文件的存储格式后, 我们还应该创建 GUI(图形用户
界面 )用于存储和读取用户信息 。 存储用户信息的图形界面
如左图所示, 读取用户信息的图形界面如右图所示 。
任务解决
一, 解决任务一 。
为了解决任务一, 一共创建了四个类, 这四个类的名称和用途如下,
1,用户类 (UserRecord)。 用户类定义了五个属性, 分别是 ID号, 姓名, 用
户类别, 基本信息和密码 。 该类用于描述用户的基本信息 。
2,图形界面类 (UserInfoUI)。 图形界面类实现了一个图形界面, 见书上图
1.3.2 (a),通过该图形界面可存储用户信息 。 该类定义了 5个标签, 分别
是 ID号, 姓名, 用户类别, 基本信息和密码, 它还定义了 5个文本输入
框, 用于输入用户信息 。
3,非法数据异常类 (IllegalDataException)。 非法数据异常类是一个自定义
的异常类, 用于数据检查, 当用户在输入框中输入了非法数据时 (例如
输入的 ID号为负数 ),将抛出该异常 。
4,存储用户信息类 (SaveRecordToFile)。 存储用户信息类使用了上面三个
类 。 该类提供的主要功能有:打开文件, 数据合法性检查, 写数据到文件, 关闭文件 。
任务解决
二, 解决任务二 。
任务二的实现原理和任务一很类似 。 为了解决任务二, 我们编写了读取用户信息类 (ReadRecordFromFile)。 读取用户信息类提供的主要功能有:
打开文件, 从文件中读数据, 关闭文件, 它使用了用户类, 图形界面列这两个类 。 运行 ReadRecordFromFile类的 main方法, 将出现如书上图
1.3.2 (b)所示的图形界面 。 因为只是读取数据, 所以输入框被设置成不
可输入数据, 只能显示数据 。
精练
请您根据前面所学知识解决任务 3。
分析:对于用户信息的更新, 我们约定, 选择 ID号作为记录键, 一个 ID号
将一条用户记录和其它用户记录区分开来 。 任务三的实现原理和任务一,
二很类似 。 为了解决任务三, 我 们需要编写更新用户信 息类(UpdateRecordToFile),并对图形界面做适当修改 。
1,修改图形界面 。 更新用户信息的图形界面如下图所示 。 和输入用户信
息的图形界面相比, 多了一个按钮 。 因此, 必须对 UserInfoUI类做适当
修改, 增加一个按钮, 并增加一个方法用于返回该按钮 。
精练
2,编写更新用户信息类 (UpdateRecordToFile)。
UpdateRecordToFile有四个重要的方法,openFile(打开文件 ),colseFile(关
闭文件 ),readRecord(读记录 )和 updateRecord(更新记录 )。 用户按下, 打
开 文 件, 按钮, 将 调 用 openFile 方法, 该 方 法 的 实 现 请 参 考
ReadRecordFromFile的 openFile方法;用户按下, 读记录, 按钮, 将调
用 readRecord方法, 该方法的实现请参考 ReadRecordFromFile的 openFile
方法;用户按下, 更新记录, 按钮, 将调用 updateRecord方法, 该方法
的实现是解决本任务的关键;用户关闭窗口, 将调用 colseFile方法, 该
方法的实现请参考 ReadRecordFromFile的 colseFile方法 。
小结
本节我们学习了如何操作文件, 主要内容如下,
一, 数据层次结构
数值 0和 1是计算机中最小的数据项, 这样的数据项称为位 (Bit)。 字符由位
构成, 字段由字符构成, 文件由字段构成 。 上述概念是建立在文件的逻辑组织形式上的, 在物理层次上, Java文件就是字节的集合 。
二, 顺序文件和随机存取文件
Java中的 File类可以用来顺序读写文件, RandomAccessFile类可用来随机
读取文件 。 RandomAccessFile类之所以能随机访问文件, 是由于它定义
了一个文件指针, 该指针指向文件的当前读 /取位置 。 通过移动这个指
针, 就可以从文件的任何位置进行读 /写操作 。
三, 文件操作
本节通过提出任务并解决任务的方式, 详细的讲述了如何在文件中写入记
录, 读出记录, 更新记录 。