58、磁盘操作与文件管理的深入解析

磁盘操作与文件管理的深入解析

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;

通过以上对磁盘扇区读写、系统级文件函数、磁盘与文件系统基础概念以及编程练习的介绍,我们对磁盘和文件操作有了全面而深入的了解。在实际应用中,可以根据这些知识进行磁盘管理、文件操作等编程任务,同时要注意遵循安全和调试原则,确保程序的正确性和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值