磁盘基础:目录结构与读写操作详解
在计算机的世界里,磁盘管理是一项至关重要的任务。了解磁盘目录结构以及如何进行磁盘扇区的读写操作,对于深入理解计算机系统的工作原理和数据存储方式具有重要意义。本文将详细介绍磁盘目录的相关知识,包括FAT和NTFS磁盘的目录结构、MS - DOS目录结构、长文件名处理以及文件分配表(FAT)的工作原理,同时还会探讨磁盘扇区的读写操作。
1. 磁盘目录概述
每一个FAT风格和NTFS磁盘都有一个根目录,它包含了磁盘上文件的主要列表。根目录中还可能包含其他目录的名称,这些目录被称为子目录。子目录可以看作是其名称出现在其他目录中的目录,而包含子目录名称的目录则被称为父目录。每个子目录又可以包含文件名和更多的目录名,最终形成一个以根目录为顶部的树状结构。
例如,在一个示例目录树中,文件的路径可以用来唯一标识文件。对于位于C盘ASM目录下SOURCE目录中的PROG1.ASM文件,其路径为C:\ASM\SOURCE\PROG1.ASM。通常,当在当前磁盘驱动器上进行输入 - 输出操作时,可以省略路径中的驱动器字母。以下是示例目录树中所有目录名的完整列表:
- C:\
- \ASM
- \ASM\LIB
- \ASM\SOURCE
- \JAVA
- \JAVA\CLASSES
- \JAVA\SOURCE
- \CPP
- \CPP\RUN
- \CPP\SOURCE
文件规范可以采用单个文件名的形式,也可以是目录路径后跟文件名,还可以在前面加上驱动器规范。
2. MS - DOS目录结构
为了更深入地了解磁盘目录,我们以MS - DOS的目录结构为例进行详细分析。每个MS - DOS目录条目长32字节,包含以下字段:
| 十六进制偏移量 | 字段名 | 格式 |
| ---- | ---- | ---- |
| 00 - 07 | 文件名 | ASCII |
| 08 - 0A | 扩展名 | ASCII |
| 0B | 属性 | 8位二进制 |
| 0C - 15 | 由MS - DOS保留 | |
| 16 - 17 | 时间戳 | 16位二进制 |
| 18 - 19 | 日期戳 | 16位二进制 |
| 1A - 1B | 起始簇号 | 16位二进制 |
| 1C - 1F | 文件大小 | 32位二进制 |
文件名字段可以保存文件、子目录或磁盘卷标的名称。第一个字节可能表示文件的状态,也可能是文件名的第一个字符。可能的状态值如下:
| 状态字节 | 描述 |
| ---- | ---- |
| 00h | 该条目从未被使用过 |
| 01h | 如果属性字节为0Fh且状态字节为01h,这是第一个长文件名条目(包含名称的最后部分、“.”和文件扩展名) |
| 05h | 文件名的第一个字符实际上是E5h字符(罕见) |
| E5h | 该条目包含文件名,但文件已被删除 |
属性字段用于标识文件的类型,它是位映射的,通常包含以下值的组合:
- 只读文件
- 隐藏文件
- 系统文件
- 卷标
- 子目录
- 存档位
- (保留,值为0)
- (保留,值为0)
存档位在文件被修改时会被设置;如果条目包含子目录的名称,则子目录位会被设置;卷标用于标识条目为磁盘卷标的名称;系统文件位表示该文件是操作系统的一部分;隐藏文件位使文件隐藏,其名称不会在目录显示中出现;只读位防止文件被删除或修改。属性值为0Fh表示当前目录条目是一个扩展文件名。
日期戳字段以位映射值的形式表示文件创建或最后更改的日期。年份值在0到119之间,会自动加上1980(IBM - PC发布的年份);月份值在1到12之间;日期值在1到31之间。时间戳字段同样以位映射值的形式表示文件创建或最后更改的时间,小时范围是0到23,分钟范围是0到59,秒以2秒为增量存储。
例如,对于一个名为MAIN.CPP的文件,其属性正常,存档位(20h)已被设置,表明文件已被修改。其起始簇号为0020h,文件大小为000004EEh字节,时间字段为4DBDh(表示9:45:58),日期字段为247Ah(表示1998年3月26日)。
3. MS - Windows中的长文件名处理
在MS - Windows中,当文件名超过8 + 3字符或使用大小写字母组合时,会分配多个磁盘目录条目。如果属性字节等于0Fh,系统会查看偏移量为0的字节。如果高字节等于4,则该条目开始一系列长文件名条目,低字节表示长文件名使用的目录条目数量。后续条目从n - 1递减到1,其中n是条目数量。
例如,对于一个26字符的文件名ABCDEFGHIJKLMNOPQRSTUV.TXT,Windows会创建三个目录条目。从01C0h的条目开始,第一个字节为01,标记该条目为长文件名条目的最后一个。后面跟着文件名的前13个字符“ABCDEFGHIJKLM”,每个Unicode字符为16位,以小端字节序存储。01A0h的条目包含长文件名的最后13个字符“NOPQRSTUV.TXT”。01E0h的条目是自动生成的短文件名,由长文件名的前六个字母、~1和原名称中最后一个点后的前三个字符组成,这些字符是1字节的ASCII码。该短文件名条目还包含文件创建日期和时间、最后访问日期、最后修改日期和时间、起始簇号以及文件大小。
4. 文件分配表(FAT)
FAT12、FAT16和FAT32文件系统使用文件分配表(FAT)来跟踪每个文件在磁盘上的位置。FAT映射磁盘簇,显示特定文件对它们的占用情况。每个条目对应一个簇号,每个簇包含一个或多个扇区。
每个文件在FAT中表示为一个链表,称为簇链。每个FAT条目包含一个整数,用于标识下一个条目。例如,有两个文件File1和File2,File1占用簇1、2、3、4、8、9和10;File2占用簇5、6、7、11和12。文件的最后一个FAT条目中的eoc(链结束)标记是一个预定义的整数值,用于标记链中的最后一个簇。
当创建文件时,操作系统会在FAT中查找第一个可用的簇条目。如果没有足够的连续簇来容纳整个文件,就会出现间隙。当文件被修改并保存回磁盘时,其簇链通常会变得更加碎片化。如果许多文件都变得碎片化,磁盘性能会开始下降,因为读写头必须在不同的磁道之间跳转以定位文件的所有簇。大多数操作系统都提供了内置的磁盘碎片整理实用程序。
5. 磁盘扇区的读写操作
INT 21h Function 7305h(绝对磁盘读写)允许读取和写入逻辑磁盘扇区。该功能仅在16位实地址模式下运行,适用于Windows 95、98和Windows Me下的FAT12、FAT16和FAT32文件系统,由于安全原因,在Windows NT、2000、XP及更高版本中不可用。
调用Function 7305h时,需要传递以下参数:
- AX:7305h
- DS:BX:DISKIO结构变量的段/偏移地址
- CX:0FFFFh
- DL:驱动器号(0 = 默认,1 = A,2 = B,3 = C等)
- SI:读写标志
DISKIO结构包含起始扇区号、要读取或写入的扇区数量以及扇区缓冲区的段/偏移地址:
DISKIO STRUCT
startSector DWORD 0 ; 起始扇区号
numSectors WORD 1 ; 扇区数量
bufferOfs WORD OFFSET buffer ; 缓冲区偏移量
bufferSeg WORD SEG buffer ; 缓冲区段
DISKIO ENDS
例如,以下代码用于从驱动器C读取一个或多个扇区:
mov ax,7305h ; 绝对读写
mov cx,0FFFFh ; 固定值
mov dl,3 ; 驱动器C
mov bx,OFFSET diskStruct ; DISKIO结构
mov si,0 ; 读取扇区
int 21h
以下代码用于向驱动器A写入一个或多个扇区:
mov ax,7305h ; 绝对读写
mov cx,0FFFFh ; 固定值
mov dl,1 ; 驱动器A
mov bx,OFFSET diskStruct ; DISKIO结构
mov si,6001h ; 写入正常扇区
int 21h
6. 扇区显示程序
为了更好地理解磁盘扇区的读写操作,我们可以编写一个程序来读取并以ASCII格式显示单个磁盘扇区。以下是该程序的伪代码:
Ask for starting sector number and drive number
do while (keystroke <> ESC)
Display heading
Read one sector
If MS - DOS error then exit
Display one sector
Wait for keystroke
Increment sector number
end do
以下是完整的16位Sector.asm程序代码:
; Sector Display Program (Sector.asm)
; Demonstrates INT 21h function 7305h (ABSDiskReadWrite)
; This Real - mode program reads and displays disk sectors.
; Works on FAT16 & FAT32 file systems running under Windows
; 95, 98, and Millenium.
INCLUDE Irvine16.inc
Setcursor PROTO, row:BYTE, col:BYTE
EOLN EQU <0dh,0ah>
ESC_KEY = 1Bh
DATA_ROW = 5
DATA_COL = 0
SECTOR_SIZE = 512
READ_MODE = 0 ; for Function 7505h
DiskIO STRUCT
startSector DWORD ? ; starting sector number
numSectors WORD 1 ; number of sectors
bufferOfs WORD OFFSET buffer ; buffer offset
bufferSeg WORD @DATA ; buffer segment
DiskIO ENDS
.data
driveNumber BYTE ?
diskStruct DiskIO <>
buffer BYTE SECTOR_SIZE DUP(0),0 ; one sector
curr_row BYTE ?
curr_col BYTE ?
; String resources
strLine BYTE EOLN,79 DUP(0C4h),EOLN,0
strHeading BYTE "Sector Display Program (Sector.exe)"
BYTE EOLN,EOLN,0
strAskSector BYTE "Enter starting sector number: ",0
strAskDrive BYTE "Enter drive number (1=A, 2=B, "
BYTE "3=C, 4=D, 5=E, 6=F): ",0
strCannotRead BYTE EOLN,"*** Cannot read the sector. "
BYTE "Press any key...", EOLN, 0
strReadingSector \
BYTE "Press Esc to quit, or any key to continue..."
BYTE EOLN,EOLN,"Reading sector: ",0
.code
main PROC
mov ax,@data
mov ds,ax
call Clrscr
mov dx,OFFSET strHeading ; display greeting
call Writestring
; ask user for...
call AskForSectorNumber
L1:
call Clrscr
call ReadSector ; read a sector
jc L2 ; quit if error
call DisplaySector
call ReadChar
cmp al,ESC_KEY ; Esc pressed?
je L3 ; yes: quit
inc diskStruct.startSector ; next sector
jmp L1 ; repeat the loop
L2:
mov dx,OFFSET strCannotRead ; error message
call Writestring
call ReadChar
L3:
call Clrscr
exit
main ENDP
;-----------------------------------------------------
AskForSectorNumber PROC
;
; Prompts the user for the starting sector number
; and drive number. Initializes the startSector
; field of the DiskIO structure, as well as the
; driveNumber variable.
;-----------------------------------------------------
pusha
mov dx,OFFSET strAskSector
call WriteString
call ReadInt
mov diskStruct.startSector,eax
call Crlf
mov dx,OFFSET strAskDrive
call WriteString
call ReadInt
mov driveNumber,al
call Crlf
popa
ret
AskForSectorNumber ENDP
;-----------------------------------------------------
ReadSector PROC
;
; Reads a sector into the input buffer.
; Receives: DL = Drive number
; Requires: DiskIO structure must be initialized.
; Returns: If CF = 0, the operation was successful;
; otherwise, CF = 1 and AX contains an
; error code.
;-----------------------------------------------------
pusha
mov ax,7305h ; ABSDiskReadWrite
mov cx,-1 ; always -1
mov bx,OFFSET diskStruct ; sector number
mov si,READ_MODE ; read mode
int 21h ; read disk sector
popa
ret
ReadSector ENDP
;-----------------------------------------------------
DisplaySector PROC
;
; Display the sector data in <buffer>, using INT 10h
; BIOS function calls. This avoids filtering of ASCII
; control codes.
; Receives: nothing. Returns: nothing.
; Requires: buffer must contain sector data.
;-----------------------------------------------------
mov dx,OFFSET strHeading ; display heading
call WriteString
mov eax,diskStruct.startSector ; display sector number
call WriteDec
mov dx,OFFSET strLine ; horizontal line
call Writestring
mov si,OFFSET buffer ; point to buffer
mov curr_row,DATA_ROW ; set row, column
mov curr_col,DATA_COL
INVOKE SetCursor,curr_row,curr_col
mov cx,SECTOR_SIZE ; loop counter
mov bh,0 ; video page 0
L1:
push cx ; save loop counter
mov ah,0Ah ; display character
mov al,[si] ; get byte from buffer
mov cx,1 ; display it
int 10h
call MoveCursor
inc si ; point to next byte
pop cx ; restore loop counter
loop L1 ; repeat the loop
这个程序首先提示用户输入起始扇区号和驱动器号,然后不断读取扇区并显示,直到用户按下Esc键退出。在读取扇区时,如果出现错误,会显示错误信息。
通过以上内容,我们对磁盘目录结构和磁盘扇区的读写操作有了更深入的了解。这些知识不仅有助于我们更好地管理磁盘上的数据,还能帮助我们理解计算机系统底层的数据存储和访问机制。在实际应用中,我们可以根据这些原理编写更复杂的磁盘管理程序,实现数据的高效存储和读取。
磁盘基础:目录结构与读写操作详解(续)
7. 磁盘相关问题解答
在前面的内容中,我们详细介绍了磁盘目录结构、长文件名处理、文件分配表以及磁盘扇区的读写操作等知识。接下来,我们将通过解答一些相关问题,进一步加深对这些内容的理解。
7.1 判断题解答
-
问题 1
:文件规范包括文件路径和文件名。(True/False)
- 答案 :True。文件规范可以是单个文件名,也可以是目录路径后跟文件名,还可以加上驱动器规范,所以该说法正确。
-
问题 2
:磁盘上的主要文件列表称为基本目录。(True/False)
- 答案 :False。磁盘上的主要文件列表存储在根目录中,而不是基本目录,所以该说法错误。
-
问题 3
:文件的目录条目包含文件的起始扇区号。(True/False)
- 答案 :False。MS - DOS目录条目中包含的是起始簇号,而不是起始扇区号,所以该说法错误。
-
问题 4
:MS - DOS目录条目中的日期字段必须加上1980。(True/False)
- 答案 :True。日期戳字段中的年份值在0到119之间,会自动加上1980(IBM - PC发布的年份),所以该说法正确。
7.2 简答题解答
-
问题 5
:MS - DOS目录条目使用多少字节?
- 答案 :每个MS - DOS目录条目长32字节。
-
问题 6
:说出MS - DOS目录条目的七个基本字段(不包括保留字段)。
-
答案
:
- 文件名(00 - 07,ASCII格式)
- 扩展名(08 - 0A,ASCII格式)
- 属性(0B,8位二进制)
- 时间戳(16 - 17,16位二进制)
- 日期戳(18 - 19,16位二进制)
- 起始簇号(1A - 1B,16位二进制)
- 文件大小(1C - 1F,32位二进制)
-
答案
:
-
问题 7
:在MS - DOS文件名条目中,识别六个可能的状态字节值。
-
答案
:
| 状态字节 | 描述 |
| ---- | ---- |
| 00h | 该条目从未被使用过 |
| 01h | 如果属性字节为0Fh且状态字节为01h,这是第一个长文件名条目(包含名称的最后部分、“.”和文件扩展名) |
| 05h | 文件名的第一个字符实际上是E5h字符(罕见) |
| E5h | 该条目包含文件名,但文件已被删除 |
| 2Eh | 该条目(.)是目录名。如果第二个字节也是2Eh(..),簇字段包含该目录的父目录的簇号 |
| 4nh | 第一个长文件名条目(包含名称的第一部分):如果属性字节为0Fh,这标记了包含单个长文件名的多个条目中的最后一个。数字n表示文件名使用的条目数量 |
-
答案
:
-
问题 8
:展示MS - DOS目录条目中时间戳字段的格式。
- 答案 :时间戳字段以位映射值的形式表示文件创建或最后更改的时间,小时范围是0到23,分钟范围是0到59,秒以2秒为增量存储。其格式为:
hours seconds minutes
0 15
-
问题 9
:当长文件名存储在卷目录中(在MS - Windows下),如何识别第一个长文件名条目?
- 答案 :如果属性字节等于0Fh,系统会查看偏移量为0的字节。如果高字节等于4,则该条目开始一系列长文件名条目,低字节表示长文件名使用的目录条目数量。
-
问题 10
:如果文件名有18个字符,需要多少个长文件名条目?
- 答案 :每个长文件名条目可以存储13个字符(除了最后一个条目可能包含“.”和扩展名),18个字符的文件名需要2个长文件名条目。
-
问题 11
:MS - Windows在原始MS - DOS文件目录条目中添加了两个新的日期字段,它们的名称是什么?
- 答案 :文件创建日期和时间、最后访问日期。
7.3 挑战题解答
-
问题 12
:说明使用簇2、3、7、6、4和8(按此顺序)的文件的文件分配表链接。
- 答案 :
FAT 条目 指向的簇
2 3
3 7
7 6
6 4
4 8
8 eoc
8. 磁盘操作总结与流程梳理
为了更清晰地展示磁盘操作的流程,我们可以使用mermaid流程图来进行梳理。
graph TD;
A[开始] --> B[询问起始扇区号和驱动器号];
B --> C[初始化DISKIO结构];
C --> D[读取扇区];
D --> E{是否出错};
E -- 是 --> F[显示错误信息];
F --> G[等待按键];
G --> H[结束];
E -- 否 --> I[显示扇区数据];
I --> J{是否按下Esc键};
J -- 是 --> H[结束];
J -- 否 --> K[增加扇区号];
K --> D[读取扇区];
这个流程图展示了磁盘扇区读取程序的主要流程:
1. 开始程序后,首先询问用户起始扇区号和驱动器号。
2. 根据用户输入初始化DISKIO结构。
3. 调用INT 21h Function 7305h读取扇区。
4. 检查读取是否出错,如果出错则显示错误信息并等待用户按键后结束程序。
5. 如果读取成功,显示扇区数据。
6. 检查用户是否按下Esc键,如果按下则结束程序,否则增加扇区号并继续读取下一个扇区。
9. 磁盘操作的实际应用与注意事项
在实际应用中,磁盘操作涉及到数据的存储和读取,需要注意以下几点:
-
兼容性问题
:INT 21h Function 7305h只适用于Windows 95、98和Windows Me下的FAT12、FAT16和FAT32文件系统,在Windows NT、2000、XP及更高版本中不可用。如果需要在这些系统中进行磁盘操作,需要使用其他方法。
-
数据安全
:任何允许读写磁盘扇区的程序都可能绕过文件和目录共享权限,因此在编写和运行此类程序时要格外小心,避免误操作导致数据丢失或损坏。
-
磁盘碎片化
:如前文所述,文件的频繁修改和删除会导致磁盘碎片化,影响磁盘性能。定期使用磁盘碎片整理工具可以优化磁盘性能。
10. 总结
通过本文的介绍,我们全面了解了磁盘目录结构、长文件名处理、文件分配表以及磁盘扇区的读写操作等知识。从FAT和NTFS磁盘的根目录开始,深入到MS - DOS和MS - Windows的目录结构,再到文件分配表的工作原理,最后学习了如何使用INT 21h Function 7305h进行磁盘扇区的读写操作,并通过扇区显示程序进行了实践。
这些知识对于理解计算机系统底层的数据存储和访问机制至关重要。在实际应用中,我们可以根据这些原理编写更复杂的磁盘管理程序,实现数据的高效存储和读取。同时,我们也需要注意磁盘操作中的兼容性、数据安全和磁盘碎片化等问题,确保磁盘数据的安全和系统的稳定运行。
希望本文能够帮助读者更好地掌握磁盘操作的相关知识,在实际工作和学习中发挥作用。
磁盘目录与读写操作解析
超级会员免费看
2万+

被折叠的 条评论
为什么被折叠?



