57、磁盘基础:目录结构与读写操作详解

磁盘目录与读写操作解析

磁盘基础:目录结构与读写操作详解

在计算机的世界里,磁盘管理是一项至关重要的任务。了解磁盘目录结构以及如何进行磁盘扇区的读写操作,对于深入理解计算机系统的工作原理和数据存储方式具有重要意义。本文将详细介绍磁盘目录的相关知识,包括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目录条目的七个基本字段(不包括保留字段)。
    • 答案
      1. 文件名(00 - 07,ASCII格式)
      2. 扩展名(08 - 0A,ASCII格式)
      3. 属性(0B,8位二进制)
      4. 时间戳(16 - 17,16位二进制)
      5. 日期戳(18 - 19,16位二进制)
      6. 起始簇号(1A - 1B,16位二进制)
      7. 文件大小(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进行磁盘扇区的读写操作,并通过扇区显示程序进行了实践。

这些知识对于理解计算机系统底层的数据存储和访问机制至关重要。在实际应用中,我们可以根据这些原理编写更复杂的磁盘管理程序,实现数据的高效存储和读取。同时,我们也需要注意磁盘操作中的兼容性、数据安全和磁盘碎片化等问题,确保磁盘数据的安全和系统的稳定运行。

希望本文能够帮助读者更好地掌握磁盘操作的相关知识,在实际工作和学习中发挥作用。

内容概要:本文围绕EKF SLAM(扩展卡尔曼滤波同步定位地图构建)的性能展开多项对比实验研究,重点分析在稀疏稠密landmark环境下、预测更新步骤同时进行非同时进行的情况下的系统性能差异,并进一步探讨EKF SLAM在有色噪声干扰下的鲁棒性表现。实验考虑了不确定性因素的影响,旨在评估不同条件下算法的定位精度地图构建质量,为实际应用中EKF SLAM的优化提供依据。文档还提及多智能体系统在遭受DoS攻击下的弹性控制研究,但核心内容聚焦于SLAM算法的性能测试分析。; 适合人群:具备一定机器人学、状态估计或自动驾驶基础知识的科研人员及工程技术人员,尤其是从事SLAM算法研究或应用开发的硕士、博士研究生和相关领域研发人员。; 使用场景及目标:①用于比较EKF SLAM在不同landmark密度下的性能表现;②分析预测更新机制同步否对滤波器稳定性精度的影响;③评估系统在有色噪声等非理想观测条件下的适应能力,提升实际部署中的可靠性。; 阅读建议:建议结合MATLAB仿真代码进行实验复现,重点关注状态协方差传播、观测更新频率噪声模型设置等关键环节,深入理解EKF SLAM在复杂环境下的行为特性。稀疏 landmark 稠密 landmark 下 EKF SLAM 性能对比实验,预测更新同时进行非同时进行对比 EKF SLAM 性能对比实验,EKF SLAM 在有色噪声下性能实验
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值