磁盘操作与文件管理的深入解析
1. 磁盘扇区的读写操作
在磁盘操作中,扇区的读写是基础且关键的部分。下面将详细介绍相关的程序和操作。
1.1 程序核心:ReadSector 过程
程序的核心是
ReadSector
过程,它使用
INT 21h Function 7305h
从磁盘读取每个扇区。读取的扇区数据会被放置在一个缓冲区中,然后通过
DisplaySector
过程进行显示。以下是相关代码示例:
ret
DisplaySector ENDP
;-----------------------------------------------
MoveCursor PROC
;
; Advance the cursor to the next column,
; check for possible wraparound on screen.
;-----------------------------------------------
cmp
curr_col,79
; last column?
jae
L1
; yes: go to next row
inc
curr_col
; no: increment column
jmp
L2
L1:
mov
curr_col,0
; next row
inc
curr_row
L2:
INVOKE Setcursor,curr_row,curr_col
ret
MoveCursor ENDP
;-----------------------------------------------------
Setcursor PROC USES dx,
row:BYTE, col:BYTE
;
; Set the screen cursor position
;-----------------------------------------------------
mov
dh, row
mov
dl, col
call
Gotoxy
ret
Setcursor ENDP
END main
1.2 使用 INT 10h 显示字符
大多数扇区包含二进制数据,如果使用
INT 21h
来显示这些数据,ASCII 控制字符会被过滤,导致显示不连贯。因此,使用
INT 10h Function 0Ah
更为合适,它能将 ASCII 码 0 到 31 作为图形字符显示。由于
Function 0Ah
不会自动移动光标,所以需要额外的代码在显示每个字符后将光标向右移动一列。
SetCursor
过程简化了
Irvine16
库中
Gotoxy
过程的实现。
1.3 扇区显示程序的变体
扇区显示程序有许多有趣的变体。例如,可以提示用户输入要显示的扇区编号范围,每个扇区可以以十六进制形式显示。还可以让用户使用
PageUp
和
PageDown
键在扇区之间前后滚动。
1.4 相关问题回顾
以下是一些关于磁盘扇区读写的常见问题及解答:
1.
判断题
:在 Windows Me 下可以使用
INT 21h Function 7305h
从硬盘读取扇区,但在 Windows XP 下不行。(答案:正确)
2.
判断题
:
INT 21h Function 7305h
仅在保护模式下读取一个或多个磁盘扇区。(答案:错误)
3.
问题
:
INT 21h Function 7305h
需要哪些输入参数?(具体参数未在当前文本中详细说明)
4.
问题
:在扇区显示程序中,为什么使用中断 10h 来显示字符?(因为大多数扇区包含二进制数据,使用
INT 21h
显示会过滤 ASCII 控制字符,导致显示不连贯,而
INT 10h Function 0Ah
能更好地处理这些字符)
5.
挑战问题
:在扇区显示程序中,如果起始扇区编号超出范围会发生什么?(未在当前文本中给出明确答案)
2. 系统级文件函数
在实地址模式下,
INT 21h
提供了一系列系统服务,用于创建和更改目录、更改文件属性、查找匹配文件等。这些服务在高级编程语言库中通常不太常见。以下是一些常用的函数介绍。
2.1 获取磁盘可用空间(7303h)
INT 21h Function 7303h
可用于查找 FAT16 或 FAT32 驱动器的磁盘卷大小和可用磁盘空间。信息会以标准结构
ExtGetDskFreSpcStruc
返回,结构定义如下:
ExtGetDskFreSpcStruc STRUC
StructSize WORD ?
Level WORD ?
SectorsPerCluster DWORD ?
BytesPerSector DWORD ?
AvailableClusters DWORD ?
TotalClusters DWORD ?
AvailablePhysSectors DWORD ?
TotalPhysSectors DWORD ?
AvailableAllocationUnits DWORD ?
TotalAllocationUnits DWORD ?
Rsvd DWORD 2 DUP (?)
ExtGetDskFreSpcStruc ENDS
各字段的简要说明如下:
-
StructSize
:返回值,表示
ExtGetDskFreSpcStruc
结构的字节大小。
-
Level
:输入和返回的级别值,必须初始化为零。
-
SectorsPerCluster
:每个簇中的扇区数量。
-
BytesPerSector
:每个扇区的字节数。
-
AvailableClusters
:可用簇的数量。
-
TotalClusters
:卷上的总簇数。
-
AvailablePhysSectors
:卷上可用的物理扇区数量,不考虑压缩。
-
TotalPhysSectors
:卷上的总物理扇区数量,不考虑压缩。
-
AvailableAllocationUnits
:卷上可用的分配单元数量,不考虑压缩。
-
TotalAllocationUnits
:卷上的总分配单元数量,不考虑压缩。
-
Rsvd
:保留成员。
调用该函数时,需要以下输入参数:
-
AX
必须等于
7303h
。
-
ES:DI
必须指向一个
ExtGetDskFreSpcStruc
变量。
-
CX
必须包含
ExtGetDskFreSpcStruc
变量的大小。
-
DS:DX
必须指向一个以空字符结尾的字符串,包含驱动器名称。可以使用 MS-DOS 类型的驱动器规范(如 “C:\”),也可以使用通用命名约定的卷规范(如 “\Server\Share”)。
如果函数执行成功,会清除进位标志并填充结构;否则,会设置进位标志。调用函数后,以下计算可能会有用:
- 要计算卷的大小(以千字节为单位),使用公式
(TotalClusters * SectorsPerCluster * BytesPerSector) / 1024
。
- 要计算卷上的可用空间(以千字节为单位),使用公式
(AvailableClusters * SectorsPerCluster * BytesPerSector) / 1024
。
以下是一个使用
INT 21h Function 7303h
获取 FAT 类型驱动器卷可用空间信息的程序示例:
; Disk Free Space
(DiskSpc.asm)
INCLUDE Irvine16.inc
.data
buffer ExtGetDskFreSpcStruc <>
driveName BYTE "C:\",0
str1 BYTE "Volume size (KB): ",0
str2 BYTE "Free space (KB): ",0
str3 BYTE "Function call failed.",0dh,0ah,0
.code
main PROC
mov
ax,@data
mov
ds,ax
mov
es,ax
mov
buffer.Level,0
; must be zero
mov
di,OFFSET buffer
; ES:DI points to buffer
mov
cx,SIZEOF buffer
; buffer size
mov
dx,OFFSET DriveName
; ptr to drive name
mov
ax,7303h
; get disk free space
int
21h
jc
error
; failed if CF = 1
mov
dx,OFFSET str1
; volume size
call
WriteString
call
CalcVolumeSize
call
WriteDec
call
Crlf
mov
dx,OFFSET str2
; free space
call
WriteString
call
CalcVolumeFree
call
WriteDec
call
Crlf
jmp
quit
error:
mov
dx,OFFSET str3
call
WriteString
quit:
exit
main ENDP
;------------------------------------------------------------
CalcVolumeSize PROC
;
; Calculate and return the disk volume size, in kilobytes.
; Receives: buffer variable, a ExtGetDskFreSpcStruc structure
; Returns: EAX = volume size
; Remarks: (SectorsPerCluster * 512 * TotalClusters) / 1024
;------------------------------------------------------------
mov
eax,buffer.SectorsPerCluster
shl
eax,9
; mult by 512
mul
buffer.TotalClusters
mov
ebx,1024
div
ebx
; return kilobytes
ret
CalcVolumeSize ENDP
;------------------------------------------------------------
CalcVolumeFree PROC
;
; Calculate and return the number of available kilobytes
; on the given volume.
; Receives: buffer variable, a ExtGetDskFreSpcStruc structure
; Returns: EAX = available space, in kilobytes
; Remarks: (SectorsPerCluster * 512 * AvailableClusters) / 1024
;-------------------------------------------------------------
mov
eax,buffer.SectorsPerCluster
shl
eax,9
; mult by 512
mul
buffer.AvailableClusters
mov
ebx,1024
div
ebx
; return kilobytes
ret
CalcVolumeFree ENDP
END main
2.2 创建子目录(39h)
INT 21h Function 39h
用于创建新的子目录。它接收一个指向以空字符结尾的字符串的指针,该字符串包含路径规范。以下是一个创建名为
ASM
的子目录的示例:
.data
pathname BYTE "\ASM",0
.code
mov
ah,39h
; create subdirectory
mov
dx,OFFSET pathname
int
21h
jc
display_error
如果函数失败,进位标志会被设置,可能的错误返回代码为 3 和 5。错误 3 表示路径中某些部分不存在,错误 5 表示提议的子目录已存在或路径中的第一个目录是根目录且已满。
2.3 删除子目录(3Ah)
INT 21h Function 3Ah
用于删除目录。它接收一个指向所需驱动器和路径的指针。如果省略驱动器名称,则假定为默认驱动器。以下是删除
C:\ASM
目录的示例:
.data
pathname BYTE 'C:\ASM',0
.code
mov
ah,3Ah
; remove subdirectory
mov
dx,OFFSET pathname
int
21h
jc
display_error
如果函数失败,进位标志会被设置,可能的错误代码为 3(路径未找到)、5(访问被拒绝:目录包含文件)、6(无效句柄)和 16(尝试删除当前目录)。
2.4 设置当前目录(3Bh)
INT 21h Function 3Bh
用于设置当前目录。它接收一个指向以空字符结尾的字符串的指针,该字符串包含目标驱动器和路径。以下是将当前目录设置为
C:\ASM\PROGS
的示例:
.data
pathname BYTE "C:\ASM\PROGS",0
.code
mov
ah,3Bh
; set current directory
mov
dx,OFFSET pathname
int
21h
jc
display_error
2.5 获取当前目录(47h)
INT 21h Function 47h
用于返回包含当前目录的字符串。它接收一个驱动器编号(
DL
)和一个指向 64 字节缓冲区的指针(
DS:SI
)。MS-DOS 会在该缓冲区中放置一个以空字符结尾的字符串,包含从根目录到当前目录的完整路径名(省略驱动器字母和前导反斜杠)。以下是获取默认驱动器当前目录路径的示例:
.data
pathname BYTE 64 dup(0)
; path stored here by MS-DOS
.code
mov
ah,47h
; get current directory path
mov
dl,0
; on default drive
mov
si,OFFSET pathname
int
21h
jc
display_error
如果函数返回时进位标志被设置,
AX
中唯一可能的错误返回代码为
0Fh
(无效驱动器规范)。
2.6 获取和设置文件属性(7143h)
INT 21h Function 7143h
用于检索或设置文件属性等任务。在 Windows 9x 中,它取代了旧的 MS-DOS
INT 21h Function 39
。将文件名的偏移量传递给
DX
。要设置文件属性,将
BL
赋值为 1,并将
CX
设置为表 15 - 8 中列出的一个或多个属性。
_A_NORMAL
属性必须单独使用,其他属性可以使用
+
运算符组合。
以下是将文件属性设置为只读和隐藏的代码示例:
mov
ax,7143h
mov
bl,1
mov cx,_A_HIDDEN + _A_RDONLY
mov
dx,OFFSET filename
int
21h
要获取文件的当前属性,将
BX
设置为 0 并调用相同的函数。属性值会以 2 的幂的组合形式返回在
CX
中。可以使用
TEST
指令评估单个属性。例如:
test cx,_A_RDONLY
jnz
readOnlyFile
; file is read-only
文件属性的含义如下表所示:
| 值 | 含义 |
| ---- | ---- |
|
_A_NORMAL (0000h)
| 文件可以读写,此值仅单独使用时有效。 |
|
_A_RDONLY (0001h)
| 文件只能读,不能写。 |
|
_A_HIDDEN (0002h)
| 文件隐藏,在普通目录列表中不显示。 |
|
_A_SYSTEM (0004h)
| 文件是操作系统的一部分或由其专用。 |
|
_A_ARCH (0020h)
| 文件是存档文件,应用程序使用此值标记文件以进行备份或删除。 |
2.7 系统级文件函数总结
以下是部分
INT 21h
磁盘服务的总结表格:
| 函数编号 | 函数名称 |
| ---- | ---- |
| 0Eh | Set default drive |
| 19h | Get default drive |
| 7303h | Get disk free space |
| 39h | Create subdirectory |
| 3Ah | Remove subdirectory |
| 3Bh | Set current directory |
| 41h | Delete file |
| 43h | Get/set file attribute |
| 47h | Get current directory path |
| 4Eh | Find first matching file |
| 4Fh | Find next matching file |
| 56h | Rename file |
| 57h | Get/set file date and time |
| 59h | Get extended error information |
2.8 系统级文件函数操作流程
下面是一个简单的 mermaid 流程图,展示了使用
INT 21h
函数进行文件和目录操作的基本流程:
graph TD;
A[开始] --> B{选择操作};
B -->|获取磁盘可用空间| C[设置参数: AX=7303h, ES:DI指向结构, CX为结构大小, DS:DX指向驱动器名];
C --> D[调用INT 21h];
D --> E{操作成功?};
E -->|是| F[计算并显示结果];
E -->|否| G[显示错误信息];
B -->|创建子目录| H[设置参数: AH=39h, DS:DX指向路径];
H --> I[调用INT 21h];
I --> J{操作成功?};
J -->|是| K[子目录创建成功];
J -->|否| L[根据错误代码处理];
B -->|其他操作| M[按对应操作设置参数并调用INT 21h];
M --> N{操作成功?};
N -->|是| O[操作完成];
N -->|否| P[显示错误信息];
F --> Q[结束];
G --> Q;
K --> Q;
L --> Q;
O --> Q;
P --> Q;
通过以上内容,我们对磁盘扇区的读写和系统级文件函数有了更深入的了解。这些操作在磁盘管理和文件操作中起着至关重要的作用。在实际应用中,需要根据具体需求选择合适的函数和方法,并注意错误处理,以确保操作的正确性和稳定性。
3. 磁盘与文件系统基础概念
3.1 磁盘物理结构
磁盘表面被格式化为同心带,称为磁道,数据以磁性方式存储在磁道上。平均寻道时间衡量从一个磁道移动到另一个磁道所花费的平均时间。磁盘性能可以通过每分钟转数(RPM)和数据传输速率(每秒从驱动器传输的数据量)来衡量。
柱面是指从读写头的单个位置可访问的所有磁道。随着时间的推移,文件在磁盘上变得更加分散,就会出现碎片化,不再存储在相邻的柱面上。
扇区是磁道的 512 字节部分。物理扇区由制造商使用所谓的低级格式化在磁盘上以磁性方式(不可见地)标记。
3.2 磁盘分区与逻辑结构
物理磁盘几何结构描述了磁盘的结构,以便系统 BIOS 能够读取。单个物理硬盘被划分为一个或多个逻辑单元,称为分区或卷。一个驱动器可能有多个分区,扩展分区可以再细分为无限数量的逻辑分区。每个逻辑分区显示为一个单独的驱动器字母,并且可能具有与其他分区不同的文件系统。主分区可以各自容纳一个可引导的操作系统。
主引导记录(MBR)在硬盘上创建第一个分区时创建,位于驱动器的第一个逻辑扇区。MBR 包含以下内容:
- 磁盘分区表,描述磁盘上所有分区的大小和位置。
- 一个小程序,用于定位分区的引导扇区,并将控制权转移到引导扇区中的程序,该程序进而加载操作系统。
3.3 文件系统
文件系统用于跟踪每个磁盘文件的位置、大小和属性。它提供了逻辑扇区到簇(所有文件和目录的基本存储单元)的映射,以及文件名和目录名到簇序列的映射。
簇是文件使用的最小空间单位,由一个或多个相邻的磁盘扇区组成。文件分配表(FAT)引用了一系列簇,该表跟踪文件使用的所有簇。
IA - 32 系统中使用的文件系统包括:
| 文件系统 | 简介 |
| ---- | ---- |
| FAT12 | 最早用于 IBM - PC 软盘。 |
| FAT16 | 是 MS - DOS 下格式化硬盘的唯一可用格式。 |
| FAT32 | 随 Windows 95 引入,并在 Windows 98 下得到改进。 |
| NTFS | 由 Windows NT、2000、XP 及更高版本支持。 |
每个 FAT 类型和 NTFS 文件系统的磁盘都有一个根目录,它是磁盘上文件的主要列表。根目录还可能包含其他目录(称为子目录)的名称。
MS - DOS 和 Windows 使用文件分配表(FAT)来跟踪每个文件在磁盘上的位置。FAT 将特定的磁盘簇映射到文件,每个条目对应一个簇号,每个簇与一个或多个扇区相关联。
4. 编程练习
以下练习必须在实地址模式下编译和运行。在测试这些程序时,务必对受影响的磁盘进行备份,或者创建一个临时磁盘。在仔细调试之前,切勿在固定磁盘上运行这些程序!
4.1 设置默认磁盘驱动器
编写一个过程,提示用户输入磁盘驱动器字母(A、B、C 或 D),然后将默认驱动器设置为用户选择的驱动器。
4.2 获取磁盘总数据空间
编写一个名为
Get_DiskSize
的过程,返回所选磁盘驱动器上的总数据空间量。输入:
AL
= 驱动器编号(0 = A,1 = B,2 = C,…)。输出:
DX:AX
= 数据空间,以字节为单位。
4.3 获取磁盘可用空间
编写一个名为
Get_DiskFreespace
的过程,返回所选磁盘驱动器上的可用空间量。输入:
DS:DX
指向包含驱动器指定符的字符串。输出:
EDX:EAX
= 磁盘可用空间,以字节为单位。编写一个程序来测试该过程,并以十六进制显示 64 位结果。
4.4 显示文件属性
编写一个名为
ShowFileAttributes
的过程,接收文件名的偏移量(
DX
),并在控制台窗口中显示文件的属性。要查找的属性包括正常、隐藏、只读和系统。提示:使用
INT 21h Function 7143h
。
编写一个程序调用
ShowFileAttributes
,并传递文件名。在运行程序之前,通过在 Windows 资源管理器中右键单击文件名,选择“属性”,并选中“隐藏”和“只读”选项来设置文件属性。或者,可以从 Windows 命令提示符运行
Attrib
命令。运行程序并验证属性显示是否正确。示例输出:
temp.txt attributes: Hidden Read - only
4.5 修改磁盘可用空间程序
修改前面提到的磁盘可用空间程序,使其显示以下信息:
Drive specification:
"C:\"
Bytes per sector:
512
Sectors per cluster:
8
Total Number of clusters:
999999
Number of available clusters:
99999
4.6 显示扇区编号
以扇区显示程序为起点,在屏幕顶部显示一个字符串,指示驱动器指定符和当前扇区编号(以十六进制表示)。
4.7 十六进制扇区显示
以扇区显示程序为起点,添加代码,让用户按 F2 以十六进制显示当前扇区,每行显示 24 个字节。每行第一个字节的偏移量应显示在该行的开头。显示将为 22 行高,最后有部分行。以下是前两行的示例,展示布局:
0000 17311625 25425B75 279A4909 200D0655 D7303825 4B6F9234
0018 273A4655 25324B55 273A4959 293D4655 A732298C FF2323DB
4.8 编程练习操作流程
下面是一个 mermaid 流程图,展示了完成编程练习的基本流程:
graph TD;
A[选择练习题目] --> B{是否需要输入参数};
B -->|是| C[设置输入参数];
B -->|否| D[直接开始编写代码];
C --> D;
D --> E[编写代码实现功能];
E --> F[编译代码];
F --> G{编译是否成功};
G -->|是| H[运行程序];
G -->|否| I[调试代码];
I --> E;
H --> J{运行结果是否正确};
J -->|是| K[完成练习];
J -->|否| I;
通过以上对磁盘扇区读写、系统级文件函数、磁盘与文件系统基础概念以及编程练习的介绍,我们对磁盘和文件操作有了全面而深入的了解。在实际应用中,可以根据这些知识进行磁盘管理、文件操作等编程任务,同时要注意遵循安全和调试原则,确保程序的正确性和稳定性。
超级会员免费看
975

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



