操作系统中的文件和目录概念
文件与文件系统
文件是信息的一种组织形式,是存储在外部存储介质上的具有标志名的一组相关信息集合。
文件系统用文件概念来组织和管理存放在各种介质上的信息。文件系统提供目录机制实现文件的“按名存取”。
目录结构与文件检索
目录是文件系统组织和管理文件的基本单位,目录中保存它所管理的每个文件的基本属性信息(成为文件目录项或文件控制块)。除了文件外,目录中还可以包含子目录和文件,子目录中还可以再有子目录和文件,由此构成目录的多级树状结构。文件是这种树状结构的叶子节点,文件中不能包含另一个文件。
在多级树状目录结构中,一个文件的全名由该文件的路径名和文件名组成。一个文件的路径名由根目录开始沿各级子目录到达该文件的路径上的所有子目录名组成。
文件的逻辑结构
文件是文件系统中最小的数据组织单位,目录机制提供文件之间的分类和组织方式。
文件的组织是指文件中信息的配置和构造方式。文件的组织包含两方面:逻辑结构和存储结构。文件的逻辑结构是从用户角度所观察到的文件中信息的组织方式,文件的存储结构是文件在外部存储器上的实际存放方式。
按照文件的逻辑结构,文件可以划分为两大类:流式文件和记录式文件。
流式文件由字节序列或字符序列组成。流式文件内的信息不再划分结构,只是具有顺序关系的一系列字节或字符集合,字节或字符是信息的最小单位。
记录式文件是一种有结构的文件,包含若干记录。记录是文件中按信息在逻辑上的独立含义划分的一个信息单位,记录在文件中的排列具有顺序关系。记录是文件内独立的最小信息单位,操作系统每次操作至少存储、检索或更新一个记录。记录可以被进一步划分为若干个更小的数据项,数据项是具有标志名的最小的不可分割的数据单位。数据项的集合构成记录,相关记录的集合构成文件。对记录的划分及对数据项的类型描述,均由应用程序完成。
文件的存取方式
存取方式是操作系统为应用程序听的使用文件的技术手段。文件类型、文件的逻辑结构决定文件的存取方式。文件的存取方式主要有顺序存取、随机存取和索引存取。
①顺序存取是指按记录顺序进行读/写操作的存取方式。
②随机存取是指按记录序号进行读/写操作的存取方式。
③索引存取是基于索引文件的存取方法。由于文件中的记录不按它在文件中的位置,而按它的记录键来编址,所以用户提供给操作系统记录键后就可查找到所需记录。
文件的使用方式
针对用户和应用程序两种不同的对象,操作系统通过操作接口和应用程序接口两种方式提供其功能和服务,对文件系统亦是如此。
①操作接口:操作系统将其功能和服务以操作命令形式提供给用户,用户以手动方式对文件系统等进行操作,实现人机交互功能。
②应用程序接口:操作系统将其功能和服务以系统调用(system call)形式提供给应用程序。
流的概念
流的定义和作用
流(stream)是指一组有顺序的、有起点和终点的字符集合,是对数据传输的总称和抽象。换言之,数据在两个对象之间的传输称为流。
对流进行读/写操作的最小单位是字节,即一次可以写入一字节或者读取一字节。提高数据传输效率的办法是,将一块内存空间设计成缓冲区(buffer),暂时存放待传送的数据,通过缓冲区可以一次读/写若干字节,缓冲区使数据能够以较大的数据块形式传送,从而能够显著地提供数据传输效率。配备缓冲区的流成为缓冲流(buffered stream)。
设计流的作用是使数据传输操作独立于相关设备。程序需要根据待传输数据的不同特性而使用不同的流,数据传输给指定设备后的操作由系统执行设备驱动程序完成。
流的存在
以下4种情况存在数据流动问题:
①控制台应用程序的标准输入/输出操作。
②文件读写操作。
③线程通信。
④网络通信。
Java的流类和文件类
按照流中元素的基本单位,流可分为字节流(binary stream)和字符流(character stream)。按照流的方向性,流可分为输入流和输出流。每种流类都有输入流和输出流两个类。
①字节流以字节为单位读/写流,用于传输非字符数据,如整数、浮点数,对象等。InputStream和OutputStream是字节输入/输出流的根类。
②字符流以字符为单位读/写流,仅用于传输字符,包括各种字符集。Reader和Write是字符输入/输出流的根类。
File文件类记载文件属性信息,RandomAccessFile随机存取文件类以随机存取方式进行文件读/写操作。
示例
从字节流中读取1字节
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) throws Exception{
String filename = "a.txt";
FileOutputStream fout = new FileOutputStream(filename);
fout.write(-1);
fout.close();
FileInputStream fin = new FileInputStream(filename);
int i;
while ((i = fin.read()) != -1){
System.out.print(i + " ");
}
fin.close();
}
}
输出结果:
255
FileOutputStream类的write(int i)方法向字节流写入int整型i的低位一字节,FileInputStream类的read()方法从字节流中读取1字节,作为一个int整数的最低1字节,并将该整数的高位3字节补0。
从字节流中读取4字节作为一个int整数
public class Main {
public static void main(String[] args) throws Exception{
String filename = "a.txt";
FileOutputStream fout = new FileOutputStream(filename);
int value = -128;
fout.write(value>>>24);
fout.write(value>>>16);
fout.write(value>>>8);
fout.write(value);
fout.close();
FileInputStream fin = new FileInputStream(filename);
while ((value = fin.read()) != -1){
int temp;
for (int i = 0; i < 3 && (temp = fin.read()) != -1; i++){
value = value << 8 | temp;
}
System.out.println(value + " ");
}
fin.close();
}
}
数据字节流读取操作:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) throws Exception{
String filename = "a.txt";
FileOutputStream fout = new FileOutputStream(filename);
DataOutputStream dout = new DataOutputStream(fout);
for (int i = 0; i < 10; i++){
dout.writeInt(i);
}
dout.close();
fout.close();
FileInputStream fin = new FileInputStream(filename);
DataInputStream din = new DataInputStream(fin);
try{
while (true){
System.out.print(din.readInt() + " ");
}
}catch (EOFException ex){
//ex.printStackTrace();
}finally{
din.close();
fin.close();
}
}
}
把一个对象的表示转换成一个字节流的过程称为序列化(serialization),反之,从字节流中重建对象的过程称为去序列化。对象能够序列化的标记是该类实现java.io.Serializable序列化接口,Serializable是标记接口,其中没有方法。如果要写入的对象没有实现序列化接口,则抛出java.io.NotSerializableException异常。
public class Main {
public static void main(String[] args) throws Exception{
String filename = "a.txt";
FileOutputStream fout = new FileOutputStream(filename);
ObjectOutputStream objout = new ObjectOutputStream(fout);
for (int i = 0; i < 10; i++){
objout.writeObject(new TreeNode((int)(Math.random() * 100)));
}
objout.close();
fout.close();
FileInputStream fin = new FileInputStream(filename);
ObjectInputStream objin = new ObjectInputStream(fin);
try{
while (true){
System.out.println(objin.readObject());
}
}catch (EOFException ex){
}finally{
objin.close();
fin.close();
}
}
}
管道字节流实现发牌程序示例:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.IOException;
public class Main {
private PipedInputStream pins[];
private PipedOutputStream pouts[];
public Main(int cardMax, int number) throws IOException{
this.pins = new PipedInputStream[number];
this.pouts = new PipedOutputStream[number];
for (int i = 0; i < number; i++){
this.pins[i] = new PipedInputStream();
this.pouts[i] = new PipedOutputStream(this.pins[i]);
}
new SendThread(this.pouts, cardMax).start();;
for (int i = 0; i < number; i++){
new ReceiveThread(this.pins[i], "PLAY" + (i + 1)).start();
}
}
public static void main(String[] args) throws Exception{
new Main(52, 4);
}
}
class SendThread extends Thread{
private PipedOutputStream pouts[];
private int cardMax;
public SendThread(PipedOutputStream pouts[], int cardMax){
this.pouts = pouts;
this.cardMax = cardMax;
this.setPriority(Thread.MAX_PRIORITY);
}
public void run(){
DataOutputStream douts[] = new DataOutputStream[this.pouts.length];
for (int i = 0; i < douts.length; i++){
douts[i] = new DataOutputStream(this.pouts[i]);
}
try{
int value = 1;
while (value <= this.cardMax){
for (int i = 0; value <= this.cardMax && i < douts.length; i++){
douts[i].writeInt(value++);
}
}
for (int i = 0; i < douts.length; i++){
douts[i].close();
this.pouts[i].close();
}
}catch(IOException ex){ ex.printStackTrace();}
}
}
class ReceiveThread extends Thread{
private PipedInputStream pin;
private String name;
public ReceiveThread(PipedInputStream pin, String name){
this.pin = pin;
this.name = name;
}
public void run(){
DataInputStream din = new DataInputStream(this.pin);
while (true){
try{
System.out.println(this.name + "取牌" + din.readInt());
Thread.sleep(100);
}
catch(IOException ex) { break; }
catch(InterruptedException ex) {}
}
try{
din.close();
this.pin.close();
}catch(IOException ex) {}
}
}
使用字符流读写文本文件示例:
public class Main {
public static void main(String[] args) throws Exception{
String filename = "b.txt";
try{
FileReader fr = new FileReader(filename);
FileWriter fw = new FileWriter("c.txt");
BufferedReader br = new BufferedReader(fr);
String line;
while ((line = br.readLine()) != null){
fw.write(line);
fw.write('\n');
}
br.close();
fr.close();
fw.close();
}catch(IOException ex){}
}
}
RandomAccessFile随机存取文件类以随机存取方式进行文件读/写操作,对一个文件可以同时进行既读又写的操作;在文件指定位置读取或者写入基本数据类型。