![]() |
中国DOS联盟-- 联合DOS 推动DOS 发展DOS --联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum |
| 游客 | 登录 | 注册 | 会员 | 搜索 | 中国DOS联盟 |
|
中国DOS联盟论坛 现在时间是 2026-08-01 21:01 |
共 48,037 主题排行 / 350,122 发帖 / 今日 2 篇 / 48,249 会员排行 |
| DOS开发编程 & 发展交流 (开发室) » 读取硬盘绝对扇区的函数(刚写的,纯DOS) |
| 可打印版本 3,306 / 15 |
| 第1楼 GOTOmsdos | 发表于 2006-06-28 00:53 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
读取硬盘绝对扇区的函数(刚写的,纯DOS) (刚写的,有8.4G限制,谁有读取137G以上的函数,贴出来学习一下,据说是扩展13终端)
#include <bios.h> #include <conio.h> #include <stdio.h> /*将读取的硬盘扇区以相应的扇区数为单位存到文件的函数(每次的读取数必须在65535字节内,否则无效)*/ void writeFile(unsigned char *buffer, unsigned int sector, char *filename) { FILE *f; if((f=fopen(filename,"ab+"))==NULL) { printf("File Error\n"); return; } fwrite(buffer,512,sector,f); fclose(f); } /*读取硬盘绝对扇区的函数(在8.4G内)*/ void readLBA(unsigned char hardDisk, unsigned long startSector, unsigned long nSector, char *filename) { unsigned char head=0; unsigned int cylinder=0; unsigned char sector=0; unsigned char pBuffer[32256]; /*63个扇区的字节数 */ FILE *f; unsigned int allowednSector=0; unsigned int doReadSector=0; unsigned long sectorWrite=0; unsigned int x=0,y=0; /*获取当前光标 */ x=wherex(); y=wherey(); if((f=fopen(filename,"wb+"))==NULL) { printf("File Error\n"); return; } fclose(f); /*把硬盘绝对扇区转换成CHS物理位置(柱面,磁头,扇区)*/ cylinder=startSector/(255*63); head=(startSector/63)%255; sector=startSector%63+1; /*算出刚开始时可有效读取的最大扇区数 */ allowednSector=63-sector+1; /*如果小的一次可以读完 */ if(nSector<=allowednSector) doReadSector=nSector; /*否则读可有效读取的最大扇区数 */ else doReadSector= allowednSector; while(sectorWrite<nSector) { /*读到缓冲 */ biosdisk(2,hardDisk,head,cylinder,sector,doReadSector,pBuffer); /*写到文件 */ writeFile(pBuffer,doReadSector,filename); sectorWrite+= doReadSector; /*显示已读的扇区数百分比 */ gotoxy(x,y); cprintf("%lu%c sectors read.",sectorWrite*100/nSector,'%'); /*磁头归为0,准备每次读63扇区(一磁道的扇区数,也正好适合fwrite()函数的范围)*/ head++;sector=1; if (head>254) {cylinder++; head=0; sector=1;} if (cylinder>1023) {printf("out of hard disk's cylinder range(0-1023)\n"); return;} doReadSector=63; /*快要读完了,不足63扇区了 */ if(nSector-sectorWrite<63) doReadSector=nSector-sectorWrite; } printf("\nDone."); } ***************************** /*以读取硬盘C盘 FAT32的FAT为例,来调用读取硬盘绝对扇区的函数 */ #include "readlba.h" /*获取FAT参数(FAT前距离DBR的扇区数,FAT所占的扇区数)*/ void getFATinfo(unsigned int hardDisk, unsigned int *reservedSector, unsigned long *sectorPerFAT) { unsigned char buffer[512]; /*获取DBR,以便 获取FAT参数 */ biosdisk(2,hardDisk,1,0,1,1,buffer); /* 获取FAT前距离DBR的扇区数 */ *reservedSector=*((unsigned int *)&buffer[0xE]); /* 获取FAT所占的扇区数 */ *sectorPerFAT=*((unsigned long *)&buffer[0x24]); } void main() { unsigned int reservedSector; unsigned long sectorPerFAT; /* 获取FAT参数 */ getFATinfo(0x80,&reservedSector,§orPerFAT); /*保存FAT到文件 */ readLBA(0x80,63+reservedSector,sectorPerFAT,"d:\\cfat.dat"); } |
|
| 第2楼 GOTOmsdos | 发表于 2006-06-28 00:55 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
测试通过。。
|
|
| 第3楼 asbai | 发表于 2006-06-28 02:24 |
| 高级用户 发帖 252 积分 653 | |
|
回楼上,读写大磁盘的中断在http://www.cn-dos.net/forum/viewthread.php?tid=21431&fpage=2里不是已经回过你了:
BIOS: INT 13h AH=42h DL=磁盘号,硬盘从80h开始 磁盘扩展读,可以应付超级大硬盘,能够寻址到2的64次方扇区。 BIOS INT 13h AH=48h DL=磁盘号,硬盘从80h开始 磁盘物理参数获取(扩展),同样支持大硬盘。 类似,扩展写是43h。。。。。 |
|
| 第4楼 GOTOmsdos | 发表于 2006-06-28 14:02 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
请问,纯DOS和相关的编译器(如 TC2,TC3)支持这个吗?
|
|
| 第5楼 asbai | 发表于 2006-06-28 14:05 |
| 高级用户 发帖 252 积分 653 | |
|
这是bios中断,慢说是纯dos,就是裸机都支持
![]() |
|
| 第6楼 GOTOmsdos | 发表于 2006-06-29 16:50 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
网上找了些资料,有 DWORD 之类东西,好像是 WIN的,
请问,这个42h,43h功能的存取是既可以用CHS的方式,也可用LBA方式 还是一定要用LBA的方式? 具体怎么处理?(比如, 在TC2,TC3,BC31)? 能不能给出代码? 我下面的代码不管用: #include <dos.h> #include <stdio.h> void main(){ unsigned char buf[512]; FILE *f; union REGS in,out; struct DiskAddressPacket { unsigned char PacketSize; // 数据包尺寸(16字节) unsigned char Reserved; // ==0 unsigned int BlockCount; // 要传输的数据块个数(以扇区为单位) unsigned long BufferAddr;// 传输缓冲地址(segment:offset) double BlockNum;// 磁盘起始绝对块地址 }; struct DiskAddressPacket dap; dap.PacketSize=16; dap.Reserved=0; dap.BlockCount=1; dap.BufferAddr=0xFFF00; dap.BlockNum=63; in.h.ah = 0x42; in.h.dl = 0x80; in.x.si = &dap; //磁盘地址数据包(Disk Address Packet) int86(0x13,&in,&out); f=fopen("int13ext.dat","wb+"); fwrite((void *)0xFFFF0,512,1,f); fclose(f); } |
|
| 第7楼 DOSforever | 发表于 2006-06-29 18:41 |
| 金牌会员 发帖 2,239 积分 4,639 | |
|
int13 的扩展调用一定要用LBA方式。实际上这个说法不对,不是 int13 要用什么方式,而是应该这么说:如果你要用到 int13 的扩展调用,你的 BIOS 和硬盘必须支持 LBA 方式。
我没怎么用过C,如果我没理解错的话,你的磁盘地址数据包的用法是错误的。DAP参数包不是写在文件上的,而是写在内存中的一个数据结构,然后你要用 DS:SI 指向这个数据结构的首地址,告诉 int13 ext: DAP 在那儿。 |
|
| 第8楼 GOTOmsdos | 发表于 2006-06-29 21:31 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
" 要用 DS:SI 指向这个数据结构的首地址"
是啊,问题可能就在这里,这个DS:SI 怎么赋值? 用C行不行? |
|
| 第9楼 GOTOmsdos | 发表于 2006-06-29 22:00 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
刚刚把 写的 功能也加进去了, 合并在一起。
(已经过测试,改了几个BUG,目前还没发现新BUG, 谁发现了,贴出来) 读写硬盘(和软盘)绝对扇区的函数: “dolba.h” #include <bios.h> #include <io.h> #include <conio.h> #include <stdio.h> void doFile(unsigned int cmd, char *doMode, unsigned char *buffer, unsigned int sector, char *filename, unsigned long sectorDone) { FILE *f; long move=sectorDone*512; if((f=fopen(filename,doMode))==NULL) { printf("File Error\n"); return; } if(cmd==2) fwrite(buffer,512,sector,f); else if(cmd==3) { fseek(f,move,0); fread(buffer,512,sector,f); } fclose(f); } void doLBA(unsigned int cmd, unsigned int hardDisk, unsigned long startSector, unsigned long nSectorVar, char *filename) { unsigned int head=0; unsigned int cylinder=0; unsigned int sector=0; unsigned char pBuffer; FILE *f; unsigned int allowednSector=0; unsigned int doReadSector=0; unsigned long sectorWrite=0; unsigned int x=0,y=0; unsigned long nSector=nSectorVar; long filesize; FILE *checkFile; x=wherex(); y=wherey(); //printf("%lu,%lu\n",startSector,nSectorVar); cylinder=((startSector+nSector-1)/(255*63)); if(cylinder>1022) { printf("\n%u out of hard disk's cylinder range(0-1022)\n",cylinder); return; } if(cmd==2) { if((f=fopen(filename,"wb+"))==NULL) { printf("File Error\n"); return; } fclose(f); } else if(cmd==3) { checkFile=fopen(filename,"rb"); filesize=filelength(fileno(checkFile)); fclose(checkFile); if((filesize==0) || (filesize % 512)!=0) {printf("the size of the file is 0 or not an integer in sectors!\n"); return; } else nSector=filesize/512; } cylinder=startSector/(255*63); head=(startSector/63)%255; sector=startSector%63+1; allowednSector=63-sector+1; if(nSector<=allowednSector) doReadSector=nSector; else doReadSector= allowednSector; while(sectorWrite<nSector) { if(bioskey(1)!=0) { if(bioskey(0)==0x11B) { printf("\nStopped.\n"); return; } } if(cylinder>1022) {printf("\nout of hard disk's cylinder range(0-1022)\n"); return;} if(cmd==2) { biosdisk(cmd,hardDisk,head,cylinder,sector,doReadSector,pBuffer); doFile(2,"ab+",pBuffer,doReadSector,filename,0); } else if(cmd==3) { doFile(3,"rb",pBuffer,doReadSector,filename,sectorWrite); biosdisk(cmd,hardDisk,head,cylinder,sector,doReadSector,pBuffer); } sectorWrite+= doReadSector; gotoxy(x,y); cprintf("%lu%c sectors done.",sectorWrite*100/nSector,'%'); head++;sector=1; if (head>254) {cylinder++; head=0; sector=1;} //if (cylinder>1022) //{printf("\nout of hard disk's cylinder range(0-1022)\n"); //return;} doReadSector=63; if(nSector-sectorWrite<63) doReadSector=nSector-sectorWrite; } printf("\nDone."); } 调用示例: dolba.c ××××××××××××××××××××××××××× #include ”dolba.h“ #include <stdlib.h> void main(int argc, char *argv) { unsigned int cmd; unsigned int hardDisk; unsigned long startLBASector; unsigned long sectorToDo; char *filename,*endptr1,*endptr2; if(argc!=6) { printf("SYNTAX: \nEXE cmd hardDisk startLBASector sectorToDo filename\n"); return; } cmd=atoi(argv); hardDisk=atoi(argv); //reservedSector=atol(argv); // sectorPerFAT=atol(argv); startLBASector=strtoul(argv,NULL,10); sectorToDo=strtoul(argv,NULL,10); filename=argv; //printf("%s,%lu,%c\n%s,%lu,%c\n",argv,startLBASector,*endptr1,argv,sectorToDo,*endptr2); /* getFATinfo(0x80,&reservedSector,§orPerFAT); */ doLBA(cmd,hardDisk,startLBASector,sectorToDo,filename); } 运行: dolba 2 128 100 200 file //从硬盘1 的100扇区处读200扇区到文件 dolba 3 128 100 200 file //把文件写到硬盘1 的100扇区处200扇区 [ Last edited by GOTOmsdos on 2006-6-29 at 22:19 ] |
|
| 第10楼 DOSforever | 发表于 2006-06-29 22:04 |
| 金牌会员 发帖 2,239 积分 4,639 | |
|
印象中 C 好象也有寄存器操作语句,但具体怎么用我也不太清楚。你看看书应该有的。或者你在 C 中调用汇编语句。
|
|
| 第11楼 GOTOmsdos | 发表于 2006-06-29 22:26 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
汇编没有学,谁知道这个扩展13中断用法的
感谢,给个代码吧,好解决这个问题。。 关键就是那个 DS:SI 的赋值。。 |
|
| 第12楼 zhgwbzhd | 发表于 2006-06-29 22:41 |
| 高级用户 发帖 187 积分 506 | |
|
还是内嵌汇编比较直观一些。
一定要用C呢,可以考虑用指针,按照规则把值付好,之后将指针只想该内存块首地址。 |
|
| 第13楼 DOSforever | 发表于 2006-06-29 23:33 |
| 金牌会员 发帖 2,239 积分 4,639 | |
|
如果你熟悉 BASIC 的话可以参考一下它的用法:
用扩展int13读取硬盘主引导区的例子 这里,我要再次感谢 qb45,不然的话我也会和他一样——“实验了N次,死鸡了N次,头发白了N根”也没搞明白到底是怎么回事。呵呵 |
|
| 第14楼 asbai | 发表于 2006-06-30 15:22 |
| 高级用户 发帖 252 积分 653 | |
|
C里一样可以处理段寄存器,参见 SREGS 结构和 int86x 调用,第一段代码扇区位置不能用double,double的存储格式是IEEE754浮点。DAP里那个是普通的64位定点整数。
第二段代码太乱了,没仔细看,估计兄台已经改正了,呵呵 [ Last edited by asbai on 2006-6-30 at 15:23 ] |
|
| 第15楼 GOTOmsdos | 发表于 2006-06-30 17:39 |
| 铂金会员 发帖 1,827 积分 5,154 | |
|
to zhgwbzhd
能不能把 内联汇编贴出来,学习一下? 让我县解决这个问题! 。。。 |
|
| 1 2 下一页 |
|
[ 联系联盟系统管理团队 -
中国DOS联盟 -
标准版 ] Sponsored by ifanr Inc | © 2001–2023 |