第四章 文件管理
7.逻辑结构VS物理结构
fopen这个函数做的事情就是打开了“test.txt”这个文件,并且“w”说明是以“写”的方式打开的,以“写”的方式打开才能往这个文件里写入数据,如果文件打开了那么fp这个指针就可以指向和这个文件相关联的一些信息,FILE这个数据结构是C语言内部已经定义好的,可以把fp这个指针理解为指向我们要操作的文件。fputs这个C语言提供的库函数可以往fp所指向的文件中写入数据,在操作完文件后需要调用fclose这个库函数来关闭文件。
如果在这个文件中要找到第16个字符,首先还是用fopen打开文件,然后调用C语言提供的库函数fseek,这个库函数做的事情就是会把文件的读写指针指向16这个位置,也就是文件的第16个字节,接下来再调用fgetc这个库函数来读出当前这个读写指针所指向位置一个字节的内容。总之可以利用fseek这个函数可以把文件的读写指针指向任何一个想要读写的位置,再利用其他函数读出若干个字节的数据。
用C语言创建顺序文件:struct这个结构体表示一个学生的信息。C语言提供的库函数fwrite可以把刚才定义的n个学生的信息,即n个struct结构体存入fp所指向的文件中,第一个参数student指明了要写入的数据的起始地址,这里其实就是student[N]这个数组的首地址(C语言中学过数组名里存放的是数组的起始地址),第二个参数指明了每一条记录占多大的空间,第三个参数指明了要写入几条记录。
现在要从文件中读出编号为5的学生的信息,调用fseek这个函数,fseek这个函数的作用会让文件的读写指针指向从开头位置开始,向后偏移5*sizeof(Student_info)这个位置。然后调用fread这个函数,第三个参数1表示读出一条记录,第二个参数表示这个记录的大小,把读出的数据赋给stu这个变量,如此便可以读出编号为5的学生的信息。
以下内容没搞懂:
刚才学生信息的例子中顺序文件采用的是顺序存储的方式,也就是这些记录逻辑上相邻的记录是一个连一个相邻的存放。其实在存储这些记录的时候当然也可以使用链式存储的方式实现,比如说当定义学生信息的时候可以再增加一个next字段,这个字段是指向了下一个学生记录的存放位置。同样可以定义一个数组来存放这些信息。0号学生的信息是存在数组下标为0的位置,可以在这个学生对应的结构体中记录下一个学生即1号学生的存放位置,1号学生存在数组下标为3的位置,所以0号学生对应的结构体中next变量的值可以设置为3,这样就相当于建立了一个指向下一个记录的指针,这就是链式存储。所有学生的数据是存放在这样的一大片的连续空间中,但是各个逻辑上相邻的学生数据又是通过链接指针的方式连在一起的,这就是所谓顺序文件的链式存储,这其实是由用户自己决定的。如果采用顺序存储的方式来存放各个学生记录,那么可以很方便的算出第i个学生记录存放的逻辑地址,然后用这个逻辑地址就可以直接命中想要找的那条记录;如果采用链式存储方式,想要找的第i个学生信息只能先读入第1个学生的信息然后一个一个往后找,其实这里和数据结构中的顺序表和链表都是一样的。总之当我们在创建一个文件的时候,我们可以自己来决定到底是用顺序存储的方式来存放这些记录,还有用链式存储的方式来存放这些记录,但无论如何在我们看来这些记录它们肯定是占用了一整片的连续空间【*】,这是从我们的视角看到的。从操作系统的视角来看,刚才我们实现的链式存储的顺序文件,其实操作系统在背后也会把它拆分为一个一个的块,然后这些物理块操作系统在背后有可能采用连续分配的方式把它们存放在磁盘中,当然也可以采用链接分配的方式把它们存放在磁盘中。这就是比较令人疑惑的点,在将逻辑结构的时候讲到顺序文件可以采用链式存储的方式,在讲物理结构的时候又讲到链接分配的方式,这两个东西看起来很像,其实文件的逻辑结构里面聊到所谓的链式存储指的是在文件的内部,这些记录的先后顺序是用链接指针把它们连起来的,这是由我们文件主自己来设计的,在文件的物理结构里面提到的所谓的链接分配,其实这个链接是操作系统做的事情,操作系统会把我们给出的一整个很大的文件拆分成一个一个的逻辑块,然后在磁盘里面存放这些逻辑块的时候操作系统会用链接的方式来记录这些逻辑块它们之间的先后顺序。可以用这个例子好好体会一下逻辑结构里的链式存储和物理结构里的链接分配它们的区别,总之在讲文件逻辑结构的时候我们谈到的链式存储,其实这些链接信息是我们用户是需要关心的,操作系统它并不关心;而文件的物理结构里面提到的链接分配,这些链接信息是操作系统需要关心的,我们用户并不需要关心。
对【*】处的那句话“在我们看来这些记录它们肯定是占用了一整片的连续空间”的理解。课本上对于顺序文件的定义:“顺序文件:文件中的记录一个接一个地顺序排列,记录通常是定长的,可以顺序存储或以链表的形式存储,在访问时需要顺序搜索文件。”从定义可以看出文件的记录在逻辑地址空间上是连续的,占用一整片连续的逻辑地址空间,在顺序存储时各个记录在逻辑上相邻,那么在逻辑地址空间上也相邻;在链式存储时,在各个记录在逻辑上相邻,但在逻辑地址空间上可以不相邻;[这里结合ppt上顺序存储和链式存储的图好理解]。但无论如何,所有的记录占用的是一整片连续的逻辑地址空间。
(基于上面的例子,自己对文件的逻辑结构和物理结构的简单理解简单说一下:文件的逻辑结构:顺序文件、索引文件、索引顺序文件都是指文件在逻辑上是怎样的关系,顺序文件中的顺序存储在定长记录下支持随机访问指的是可以直接得到第i条记录的逻辑地址,将第i条记录的逻辑地址传给操作系统,操作系统将其分为逻辑块号、块内地址,然后操作系统负责实现逻辑块号到物理块号的转变,得到最终的物理地址,取出数据;顺序文件的链式存储不支持随机访问指的是不能直接得到第i条记录的逻辑地址,只能依次读入0到i-1条记录,第i-1条记录中保存了指向第i条记录的指针,然后得到第i条记录的逻辑地址,同上,操作系统负责实现逻辑地址到物理地址的转变,得到最终的物理地址,取出数据。文件的物理结构:连续分配,链接分配、索引分配(索引链接、多层索引、混合索引)指的是文件的数据是如何存放在磁盘上的,文件的磁盘块之间如何联系起来。物理结构上支持随机访问指的是可以直接命中要访问的磁盘块。在链接分配的隐式链接(除最后一个磁盘块外,各磁盘块中保存了指向下一个磁盘块的链接指针)中,FCB中保存了起始块号,要访问逻辑块号为i的磁盘块,必须先访问0号逻辑块(FCB中保存了0号逻辑块的磁盘块号即起始块号),得到1号逻辑块的磁盘块号,访问1号逻辑块得到2号逻辑块的磁盘块号…以此类推,读入i-1号逻辑块得到i号逻辑块的磁盘块号,再访问i号逻辑块,从中可以知道隐式链接不支持随机访问。而在显式链接中,要访问i号逻辑块通过查询FAT表可以找到i号逻辑块对应的磁盘块号,因此可以直接访问i号逻辑块,而不必依次读入0到i-1号逻辑块,所以显式链接是支持随机访问的。)