FAT12模拟-C语言读取
介绍
之前详细介绍了FAT12文件系统
其中涉及到过多位运算的时间处理问题,我在另一篇文章中进行了分析。并且附有C语言代码。
DOS的镜像就是FAT12文件系统,在网络上有freedos,操作跟DOS大同小异,可以免费下载
DOS原版的镜像我放在百度云里面了,提取码far8
视频演示
CSDN放不了
友情提示:做实验可以先把代码copy下来,把代码和DOS的镜像放在同一目录下运行一下,感受DOS的快感。不然几千行代码很劝退的。代码,要在wsl运行。
实现的功能
虽然说是仿真FAT12文件系统,实际上把很多DOS的功能都实现出来了。说白了也就是DOS的C语言仿真。这篇文章介绍读取FAT12文件系统的内容,不对磁盘进行修改。
仿真,实现了如下命令(只是很基础的命令,不能加参数)
命令 | 说明 |
---|---|
dir | 暂时无法使用绝对路径 |
cd | 相对路径只能进入一个文件夹,可用绝对路径 |
type | 查看当前文件内某文件,或者用绝对路径 |
基本结构
首先整个操作系统是用C语言写成,基本的思路是,把一个函数当作一个程序。只是仿真文件系统,打开文件表、活动文件表……等数据结构统统没有。
基本的思路是main()调用boost_system()函数。boost_system()函数再调用cmd()函数。cmd()函数就读取各个命令,然后调用对应指令的函数,比如directory(), change_directory(), type()
下面是一个示意图
仿真的主干过程就是写各种cmd命令行中的函数,毕竟DOS系统就是通过命令行执行各种程序。
启动操作系统的相关操作
在方阵程序中启动操作系统就是:
(1)打开FAT软盘
(2)读取MBR区的数据
(3)调用cmd程序
打开FAT软盘
打开FAT软盘就是是用C语言打开二进制文件的函数,赋值给文件指针。
FILE *fat12_file = fopen(disk, "rb");
由于是打开的二进制文件,因此在读写过程中涉及到很多的调整文件指针位置的操作,涉及到函数fseek、fread、fwrite。
int fseek(FILE *fp, long offset, int origin);
unsigned fread (void *buf, unsigned size, unsigned count, FILE* fp);
unsigned fwrite (const void *bufAunsigned size,unsigned count,FILE* fp);
fseek作用是调整文件指针的位置。第一个参数为文件指针,第二个参数是偏移的字节数,第三个参数是开始偏移的地址:SEEK_SET表示从文件头开始(SEEK_END表示从文件末尾开始,SEEK_CUR表示从当前位置开始)。
fread的作用是读取一定的字节数到buf中。第一个参数是存储读取数据的指针,第二个参数指定了一次读取size个字节,第三个参数指定一共读取count次,第四个参数为文件指针。
fwrite的作用是写入一定字节到文件中。参数的含义和fread相似。
更多的文件操作细节见C语言文件操作完全攻略
读取MBR数据
首先要定义结构header,按顺序储存MBR区的各种数据,不论仿真程序是否使用到。我们可以用下面一条指令,将所有的MBR数据存储在对应的变量中。
fread(&fat_head, sizeof(char), BYTE_PER_BLOCK, fat12_file);
fat_head就是按顺序声明好的结构,结构体的定义如下。要使用#pragma(1)取消对齐,这样才能让MBR区的数据对号入座。
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#pragma pack (1)
//数据段
struct header
{//跳转指令char jmp[3];// 厂商名 yxros1.0char BS_OEMName[8];// 每个扇区字节数 512u16 BPB_BytesPerSec;// 每簇扇区数 1u8 BPB_SecPerClus;//boot引导占扇区数 1u16 BPB_ResvdSecCnt;//一共有几个FAT表 2u8 BPB_NumFATs;//根目录文件最大数 0xe0 = 224u16 BPB_RootEntCnt;//扇区总数 0xb40 = 2880u16 BPB_TotSec16;//介质描述 0xf0u8 BPB_Media;//每个FAT表占扇区数 9u16 BPB_FATSz16;// 每个磁道占扇区数 0x12u16 BPB_SecPerTrk;// 磁头数 0x2u16 BPB_NumHeads;// 隐藏扇区数 0u32 BPB_HiddSec;// 如果BPB_TotSec16=0,则由这里给出扇区数 0u32 BPB_TotSec32;// INT 13H的驱动号 0u8 BS_DrvNum;//保留,未用 0u8 BS_Reserved1;//扩展引导标记 0x29u8 BS_BootSig;// 卷序列号 0u32 BS_VollD;// 卷标 'yxr620'u8 BS_VolLab[11];// 文件系统类型 'FAT12'u8 BS_FileSysType[8];//引导代码char code[448];//结束标志char end_point[2];// 防止各种对齐现象,取消对齐,读写比较方便
}__attribute__((packed)) fat_head;
调用cmd
直接调用cmd函数即可,cmd函数的定义也附在下面:
void cmd(FILE *fat12_file);
cmd程序
cmd程序读取每一行命令,然后根据不同的命令调用不同的函数,来执行相应指令。
分析指令
直接使用下面函数,把每种指令转化成对应的操作码,然后cmd直接根据不同的操作码调用不同的指令。
#define _DIR 1
#define _CD 2
#define _SHUT 3
#define _TYPE 4
#define _COPY 5
#define _DEL 6
#define _MKDIR 7
#define _RMDIR 8int decode_operation(char *operation)
{// 将小写指令转成大写指令small2big(operation);// printf("%s", operation);if(!strcmp(operation, "DIR")) return _DIR;else if(!strcmp(operation, "CD")) return _CD;else if(!strcmp(operation, "SHUT")) return _SHUT;else if(!strcmp(operation, "TYPE")) return _TYPE;else if(!strcmp(operation, "COPY")) return _COPY;else if(!strcmp(operation, "DEL")) return _DEL;else if(!strcmp(operation, "MKDIR")) return _MKDIR;else if(!strcmp(operation, "RMDIR")) return _RMDIR;return 0;
}
设计指令的基本原则
除了cd指令,其他指令都不能改变当前的路径,这些操作都使用temp_path来表示真正操作的路径。temp_path初始化为current_path,绝对路径、相对路径对路径的更改都发生在temp_path上。
指令后跟的路径情况非常复杂。下面函数专门分离路径名称并且将temp_path调整到对应的路径上去。
第一个参数为当前路径的指针;
第二个参数为储存FAT12文件系统的文件指针;
第三个参数可能是要操作的目录名称,也可能是绝对路径。
// 用来给direcotry等函数分离绝对路径,也可以分离相对路径
void split_path_direcotry(struct PATH *temp_path_ptr, FILE *fat12_file,\char *file_name);
具体说一下struct PATH。
PATH_Arr:从根目录到当前目录每个目录的名称;
PATH_Length:当前目录的深度,根目录为1;
BASE:当前目录起始地址(在FAT软盘上的地址)
SIZE:该目录一共占有的字节数,为512字节的整倍数
//保存当前路径的结构
struct PATH
{// 储存路径的数组char PATH_Arr[100][11];// 储存当前已经有多少个路径,根目录为A,长度为1int PATH_Length;// 首扇区的地址int BASE;// 该目录项大小(字节为单位)int SIZE;
};
dir指令
dir指令可以使用绝对路径和相对路径,也可以直接用dir指令输出当前目录的文件信息。下面是该指令对应函数的签名。
第一个参数是存储当前路径信息的结构体指针;
第二个参数为储存FAT12文件系统的文件指针。
// 进行DIR操作
void directory(struct PATH *current_path_ptr, FILE *fat12_file);
首先使用split_path_directory函数将temp_path调整到对应的目录中,接下来就可以循环输出。temp_path指向的目录所有文件以下面的格式输出。可以看到,输出跟DOS基本一样,跟Windows的命令也基本一样,就是日期等信息被Windows的命令行放在了前面。
循环遍历每一个文件目录项的过程如下
int base = temp_path.BASE;for(i = 0; i < temp_path.SIZE / 32; ++i){struct ROOT_ENTRY temp_entry;// 将文件指针,放在根目录开头处fseek(fat12_file, base, SEEK_SET);//读取一个目录项fread(&temp_entry, 1, 32, fat12_file);base += 32; // 不用输出空目录项,或者已删除的文件if(temp_entry.DIR_Name[0] == '\0' || temp_entry.DIR_Name[0] == 0xe5)continue;// 不用输出隐藏文件if(temp_entry.DIR_Attr == 0x27) continue;// 输出文件名和扩展名int j;for (j = 0; j < 12; ++j)printf("%c", temp_entry.DIR_Name[j]);// 输出文件大小或者文件夹<dir>if(temp_entry.DIR_Attr == 0x10) printf("%-20s ", "<DIR>");else printf("%20d", temp_entry.DIR_FileSize);//输出日期和时间print_date(temp_entry.DIR_WriDate);print_time(temp_entry.DIR_WriTime);printf("\n");}
cd指令
cd指令的全称为change_directory,可以使用绝对路径和相对路径。该操作的函数原型如下:
第一个参数是当前目录的指针,也就是要改变的量;
第二个参数是FAT12软盘的文件指针;
第三个参数是要进入的路径,可以是相对路径也可以是绝对路径。
// 进入目录操作
// 这个函数本身只是改变current_path_ptr的函数
// 很多其他操作都可以使用这个函数
void change_directory(struct PATH *current_path_ptr,\FILE *fat12_file, char *subdirectory);
type指令
type指令可使用相对路径,也可用绝对路径。type指令的函数签名如下:
第一、二个参数和上面的命令一样;
第三个参数是文件名,或者文件名和绝对路径的组合。
// type指令,输出该文件的所有内容
void type_command(struct PATH *current_path_ptr, FILE *faT12_file,\char *file_name);
FAT12模拟-C语言读取相关推荐
- C语言读取bmp图像并做简单显示
C语言读取bmp图像并做简单显示) bmp文件格式 读取bmp文件信息并展示 bmp文件格式 bmp文件大体上分为四个部分: bmp文件构成 位图文件头BITMAPFILEHEADER 位图信息头BI ...
- R语言|1.4 R语言读取数据(csv,txt,xlsx)
R语言|1.4 R语言读取数据(csv,txt,xlsx) 1.4.1获取R的内置数据集 1.4.2模拟特定分布数据 1.4.3导入数据 1)导入txt与csv 2)导入xls与xlsx 1.4.1获 ...
- R语言读取excel文件实战(read.xlsx函数、read_excel函数、read.xlsx函数、Write函数)
R语言读取excel文件实战(read.xlsx函数.read_excel函数.read.xlsx函数.Write函数) 目录 R语言读取excel文件实战(read.xlsx函数.read_exce ...
- 汇编:模拟C语言实现break与continue
1 ;=============================== 2 ;循环程序设计 3 ;模拟C语言实现break 与continue 4 DATAS SEGMENT 5 i dw 0 6 su ...
- R语言读取出现 列的数目比列的名字要多的解决方法
R语言读取出现 列的数目比列的名字要多的解决方法 参考文章: (1)R语言读取出现 列的数目比列的名字要多的解决方法 (2)https://www.cnblogs.com/cyh1989/p/9112 ...
- 深入解析JNA—模拟C语言结构体
原帖:http://blog.csdn.net/shendl/article/details/3599849 深入解析JNA-模拟C语言结构体 前言 前几天写<JNA--JNI终结者>一文 ...
- 使用C语言读取properties文件V1.0
本程序使用C语言读取类似以下格式的properties文件. path = /etc/wgetrc launch_on_start = true 下一版目标: (1)使用指针代替二维数据或者二维数据的 ...
- 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)
版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 I ...
- r语言读取excel数据_R语言 | 更快的表格文件读取方法!
友情提示:蓝色下划线字体为引文,请保持警惕! 使用R语言读取 Affymetrix Human Exon 1.0 ST Array 芯片平台探针注释文件: https://www.affymetrix ...
最新文章
- mysql可以打开dbt么_dbt 基本试用
- socket通信(1)概述
- 什么是爱?[转载朋友发给我的信息]
- Linux下VTK、ITK的安装及运行 转载
- 时间更新服务器推荐 - NTP时间同步服务器集群:ntp.api.bz
- 上传图片预览,支持IE6
- JAVA入门级教学之(方法-6)
- Spring JSF集成教程
- 六时出行 App 隐私政策
- 如何判断Linux服务器是否被入侵?
- java int stack_java中int算法的有趣现象
- java应用商店,API for Java 8
- 超级卡特兰数(bzoj 4706: B君的多边形)
- NSString的形式--可变字符串--查方法
- sql常识-LEFT JOIN
- 苍狼敏捷软件开发团队建设指南-2-团队建设
- 三维扫描仪为媒,虚拟试衣间下嫁普通制衣生产厂家
- 简洁界面清爽让人非常舒服的一款短视频去水印微信小程序源码自带接口支持多种流量主
- iis 安装完ssl 证书谷歌浏览器还是提示不安全的解决方法
- 2002普及组第四题过河卒
热门文章
- HyperLedger Fabric中Fabric-CA的使用
- D2550运行Linux,也发一个128*128的相框lcd4linux的conf
- mysql中add_months_oracle中add_months()函数总结
- Leetcode各种题型题目+思路+代码(共176道题)
- 背景图片和颜色混合叠加多种混合模式
- CentOS 6.4 安装极点五笔输入法
- 浅谈现在完成时被动语态
- 大三老学姨想说。。。
- 线性代数之矩阵的秩(2)
- FlexRay总线原理及应用