磁盘目录与扇区读写全解析
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 | 该条目包含文件名,但文件已被删除 |
| 2Eh | 条目“.”表示目录名。如果第二个字节也是2Eh(“..”),簇字段包含该目录父目录的簇号 |
| 4nh | 第一个长文件名条目(包含名称的第一部分):如果属性字节为0Fh,这标志着包含单个长文件名的多个条目的最后一个。数字n表示文件名使用的条目数 |
属性字段用于识别文件类型,它是位映射的,通常包含以下值的组合:
- 只读文件
- 隐藏文件
- 系统文件
- 卷标
- 子目录
- 存档位
- 保留位(必须为0)
日期戳字段表示文件创建或最后更改的日期,以位映射值表示。年份值在0到119之间,会自动加上1980年。月份值在1到12之间,日期值在1到31之间。
时间戳字段表示文件创建或最后更改的时间,同样以位映射值表示。小时范围是0到23,分钟范围是0到59,秒以2秒为增量存储,范围是0到59。例如,二进制值10100等于40秒。
3. MS - Windows中的长文件名
在MS - Windows中,长于8 + 3字符的文件名或使用大小写字母组合的文件名会被分配多个磁盘目录条目。如果属性字节等于0Fh,系统会查看偏移量为0的字节。如果高字节等于4,这个条目将开始一系列长文件名条目,低字节表示长文件名使用的目录条目数。后续条目从n - 1递减到1,其中n是条目数。
例如,对于26个字符的文件名
ABCDEFGHIJKLMNOPQRSTUV.TXT
,Windows会创建三个目录条目:
| 状态字节 | 描述 |
| — | — |
| 43 | 表示长文件名总共使用三个条目,此条目包含文件名的最后部分、“.”和三个字符的扩展名 |
| 02 | 包含文件名的第二部分 |
| 01 | 包含文件名的第一部分 |
4. 文件分配表(FAT)
FAT12、FAT16和FAT32文件系统使用文件分配表(FAT)来跟踪每个文件在磁盘上的位置。FAT映射磁盘簇,显示特定文件对它们的占用情况。每个条目对应一个簇号,每个簇包含一个或多个扇区。
每个文件在FAT中表示为一个链表,称为簇链。每个FAT条目包含一个整数,用于标识下一个条目。当文件创建时,操作系统会在FAT中查找第一个可用的簇条目。如果没有足够的连续簇来容纳整个文件,就会出现间隙。当文件被修改并保存回磁盘时,其簇链通常会变得更加碎片化。如果许多文件都变得碎片化,磁盘性能会开始下降,因为读写头必须在不同的磁道之间跳转来定位文件的所有簇。大多数操作系统都提供了内置的磁盘碎片整理实用程序。
5. 磁盘扇区的读写
INT 21h Function 7305h(绝对磁盘读写)允许你读写逻辑磁盘扇区。该功能仅在16位实地址模式下运行,适用于Windows 95、98和Windows Me下的FAT12、FAT16和FAT32文件系统,由于安全原因,在Windows NT、2000、XP及更高版本中不可用。
调用Function 7305h时,需要传递以下参数:
- 一个DISKIO结构,包含起始扇区号、要读写的扇区数以及扇区缓冲区的段/偏移地址。
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格式内容。该程序运行在Windows 95、98和Me的实地址模式下,由于磁盘访问的安全限制,在Windows NT、2000、XP及更高版本中不可用。
; 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 ? ; 起始扇区号
numSectors WORD 1 ; 扇区数
bufferOfs WORD OFFSET buffer ; 缓冲区偏移
bufferSeg WORD @DATA ; 缓冲区段
DiskIO ENDS
.data
driveNumber BYTE ?
diskStruct DiskIO <>
buffer BYTE SECTOR_SIZE DUP(0), 0 ; 一个扇区
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 ; 显示问候语
call Writestring
; 询问用户
call AskForSectorNumber
L1:
call Clrscr
call ReadSector ; 读取一个扇区
jc L2 ; 如果出错则退出
call DisplaySector
call ReadChar
cmp al, ESC_KEY ; 是否按下Esc键
je L3 ; 是则退出
inc diskStruct.startSector ; 下一个扇区
jmp L1 ; 重复循环
L2:
mov dx, OFFSET strCannotRead ; 错误信息
call Writestring
call ReadChar
L3:
call Clrscr
exit
main ENDP
;-----------------------------------------------------
AskForSectorNumber PROC
;
; 提示用户输入起始扇区号和驱动器号。初始化DiskIO结构的startSector字段以及driveNumber变量。
;-----------------------------------------------------
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
;
; 将扇区数据读入输入缓冲区。
; 接收:DL = 驱动器号
; 要求:DiskIO结构必须初始化。
; 返回:如果CF = 0,操作成功;否则,CF = 1且AX包含错误代码。
;-----------------------------------------------------
pusha
mov ax, 7305h ; ABSDiskReadWrite
mov cx, -1 ; 总是 -1
mov bx, OFFSET diskStruct ; 扇区号
mov si, READ_MODE ; 读取模式
int 21h ; 读取磁盘扇区
popa
ret
ReadSector ENDP
;-----------------------------------------------------
DisplaySector PROC
;
; 使用INT 10h BIOS函数调用显示<buffer>中的扇区数据,避免过滤ASCII控制代码。
; 接收:无。返回:无。
; 要求:buffer必须包含扇区数据。
;-----------------------------------------------------
mov dx, OFFSET strHeading ; 显示标题
call WriteString
mov eax, diskStruct.startSector ; 显示扇区号
call WriteDec
mov dx, OFFSET strLine ; 水平线
call Writestring
mov si, OFFSET buffer ; 指向缓冲区
mov curr_row, DATA_ROW ; 设置行、列
mov curr_col, DATA_COL
INVOKE SetCursor, curr_row, curr_col
mov cx, SECTOR_SIZE ; 循环计数器
mov bh, 0 ; 视频页面0
L1:
push cx ; 保存循环计数器
mov ah, 0Ah ; 显示字符
mov al, [si] ; 从缓冲区获取字节
mov cx, 1 ; 显示它
int 10h
call MoveCursor
inc si ; 指向下一个字节
pop cx ; 恢复循环计数器
loop L1 ; 重复循环
ret
DisplaySector ENDP
7. 相关问题解答
-
判断题:
- 文件规范包括文件路径和文件名。(True)
- 磁盘上文件的主要列表称为基目录。(False,应是根目录)
- 文件的目录条目包含文件的起始扇区号。(False,包含起始簇号)
- MS - DOS目录条目中的日期字段必须加上1980。(True)
-
简答题:
- MS - DOS目录条目使用多少字节?(32字节)
- 列出MS - DOS目录条目的七个基本字段(不包括保留字段)。(文件名、扩展名、属性、时间戳、日期戳、起始簇号、文件大小)
- 在MS - DOS文件名条目中,识别六个可能的状态字节值。(00h、01h、05h、E5h、2Eh、4nh)
- 显示MS - DOS目录条目中时间戳字段的格式。(小时范围0 - 23,分钟范围0 - 59,秒以2秒为增量,范围0 - 59)
- 当长文件名存储在卷目录中(在MS - Windows下),如何识别第一个长文件名条目?(如果属性字节为0Fh且偏移量为0的字节高字节为4,该条目为第一个长文件名条目,低字节表示使用的条目数)
- 如果文件名有18个字符,需要多少个长文件名条目?(2个)
- MS - Windows在原始MS - DOS文件目录条目中添加了两个新的日期字段,它们的名称是什么?(文件创建日期和最后访问日期)
-
挑战题:
- 说明使用簇2、3、7、6、4和8的文件的文件分配表链接。(2 -> 3 -> 7 -> 6 -> 4 -> 8 -> eoc)
- 如果磁盘的簇大小为8 KByte,存储一个8200字节的文件会有多少字节的浪费空间?(8192字节为一个簇,8200 - 8192 = 8字节,浪费8192 - 8200 + 8192 = 8184字节)
- 解释NTFS如何存储稀疏文件。(需要访问Microsoft MSDN网站查找相关信息)
通过上述内容,我们详细了解了磁盘目录的结构、文件分配表的工作原理以及磁盘扇区的读写方法。这些知识对于理解磁盘存储和文件管理至关重要。无论是在学习计算机底层原理还是进行磁盘相关的编程开发,都能提供有力的支持。
磁盘目录与扇区读写全解析
8. 磁盘操作流程总结
为了更清晰地理解磁盘目录和扇区读写操作,我们可以将相关流程总结如下:
8.1 磁盘目录操作流程
graph TD
A[识别磁盘类型] --> B{FAT或NTFS}
B -- FAT风格 --> C[定位根目录]
B -- NTFS --> C
C --> D[查找文件或子目录]
D --> E{找到?}
E -- 是 --> F[获取文件或目录信息]
E -- 否 --> G[提示未找到]
8.2 扇区读写操作流程
graph TD
A[选择操作系统] --> B{FAT12/16/32且Win95/98/Me}
B -- 是 --> C[准备DISKIO结构]
B -- 否 --> D[提示不支持]
C --> E{读或写}
E -- 读 --> F[设置SI为读模式]
E -- 写 --> G[设置SI为写模式]
F --> H[调用INT 21h Function 7305h]
G --> H
H --> I{操作成功?}
I -- 是 --> J[完成操作]
I -- 否 --> K[显示错误信息]
9. 磁盘性能优化建议
磁盘碎片化是影响磁盘性能的重要因素之一。当文件的簇链变得碎片化时,磁盘读写头需要在不同磁道间频繁跳转,从而降低读写速度。为了优化磁盘性能,我们可以采取以下措施:
-
定期进行磁盘碎片整理 :大多数操作系统都提供了内置的磁盘碎片整理工具。以Windows系统为例,操作步骤如下:
- 打开“此电脑”,右键单击需要整理的磁盘,选择“属性”。
- 在弹出的属性窗口中,切换到“工具”选项卡。
- 在“优化和碎片整理驱动器”区域,点击“优化”按钮。
- 系统会自动分析磁盘碎片情况,并根据需要进行整理。
-
合理规划文件存储 :尽量将相关的文件存储在相邻的簇中,避免文件碎片化。例如,将一个项目的所有文件存储在同一个文件夹中,而不是分散在不同的磁盘位置。
10. 长文件名处理的注意事项
在MS - Windows中处理长文件名时,需要注意以下几点:
- 兼容性问题 :由于MS - DOS不支持长文件名,当使用属性字节为0Fh的长文件名时,MS - DOS会自动忽略这些文件。因此,在与MS - DOS系统交互时,需要考虑文件名的兼容性。
- 条目管理 :长文件名会占用多个磁盘目录条目,因此在磁盘空间有限的情况下,需要合理管理长文件名的使用,避免过多占用磁盘空间。
11. 代码优化思路
对于前面提到的扇区显示程序,我们可以从以下几个方面进行优化:
- 错误处理优化 :当前程序在读取扇区出错时,只是简单地显示错误信息并等待用户按键。可以进一步优化错误处理逻辑,例如记录错误日志,方便后续排查问题。
- 用户交互优化 :可以增加更多的用户交互功能,例如允许用户指定显示的扇区数量,而不是每次只显示一个扇区。
以下是优化后的部分代码示例:
; 增加错误日志记录功能
.data
errorLog BYTE 100 DUP(0) ; 错误日志缓冲区
.code
; 优化后的ReadSector过程
ReadSector PROC
pusha
mov ax, 7305h ; ABSDiskReadWrite
mov cx, -1 ; 总是 -1
mov bx, OFFSET diskStruct ; 扇区号
mov si, READ_MODE ; 读取模式
int 21h ; 读取磁盘扇区
jc ErrorHandler ; 如果出错,跳转到错误处理程序
popa
ret
ErrorHandler:
mov dx, OFFSET errorLog
mov [dx], al ; 记录错误代码
mov [dx + 1], ah
mov dx, OFFSET strCannotRead
call Writestring
call ReadChar
popa
ret
ReadSector ENDP
12. 总结
通过对磁盘目录和扇区读写的深入学习,我们了解了磁盘存储的基本原理和相关操作方法。从磁盘目录的树状结构、MS - DOS和MS - Windows的文件名处理方式,到文件分配表的工作机制,再到磁盘扇区的读写操作,每一个环节都紧密相连,共同构成了磁盘存储和文件管理的基础。
在实际应用中,我们可以根据不同的需求和场景,灵活运用这些知识。例如,在开发磁盘管理工具时,需要准确处理文件目录和扇区读写;在进行磁盘性能优化时,需要关注文件碎片化问题。同时,我们还可以通过优化代码和合理规划磁盘使用,提高磁盘操作的效率和稳定性。
希望本文能够帮助读者更好地理解磁盘存储和文件管理的相关知识,为进一步的学习和实践提供参考。
超级会员免费看
807

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



