实验十:获取磁盘基本信息
一、实验目的
(1) 了解磁盘的物理组织。
(2) 熟悉Windows 系统如何查看磁盘相关系数。
(3) 掌握Windows 系统提供的有关对磁盘操作 API。
二、实验准备
1.相关系数数据结构说明
磁盘基本物理结构原型:
Typedef struct _DTSK_GEOMETRY {
LARGE_INTEGER Cylinders;
MEDIA_TYPE MediaType;
DWORD TracksPerCylinder;
DWORD SectorsPerTrack;
DWORD BytesPerSector;
} DISK_GEOMETRY;
成员说明:
(1)Cylinders:磁盘的柱面数。
(2)MediaType:介质类型,如3.5英寸,1.44MB软盘。
(3)TracksPerCylinder :每个柱面的磁道数。
(4)SectorsPerTrack:每个磁道的扇区数。
(5)BytesPerSector:每个扇区的字节数。
2.相关API 函数介绍
(1)文件创建
函数CreateFile()用于打开磁盘驱动器并返回一个文件句柄,这里驱动器被当做文件来处理。有关文件操作函数的详细说明参见4.1.2节。
原型:
HANDLE CreateFile(
LPCTSTE lpFileName, //指向文件名的指针
DWORD dwDesiredAccess, //读/写访问模式
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
DWORD dwCreateionaDisposition, //文件存在标志
DWORD dwFlagsAndAttributes, //文件属性
HANDLE hTemplateFile //指向访问模板文件的句柄
);
(2)获取磁盘的基本信息
函数DeviceIoControl() 用于获取磁盘的基本信息
原型:
BOOL DeviceIoControl(
HANDLE hDevice, //设备句柄
DWORD dwIoControlCode, //操作控制代码
LPVOID lpInBuffer, //输入数据缓冲区
DWORD nInBufferSize, //输入数据缓冲区大小
LPVOID lpOutBuffer, //输出数据缓冲区
DWORD nOutBufferSize, //输出数据缓冲区大小
LPDWORD lpBytesReturned, //可获取的字节计数
LPOVERLAPPED lpOverlapped, //指向OVERLAPPED结构的指针
);
参数说明:
1 hDevice: 目标设备的句柄,由CreateFile() 函数获得。
2 dwIoControlCode: 指定操作的控制信息,用该值可以辨别将要执行的操作,以及对哪类设备进行操作。该参数取值如表所示
dwIoControlCode 的值
值 | 描述 |
---|---|
IOCTL_DISK_GET_DRIVE_GEOMETRY | 得到磁盘物理结构信息 |
IOCTL_DISK_GET_PARTITION_INFO | 得到磁盘分区信息 |
FSCTL_QUERY_FAT_BPB | 返回FAT16或FAT12卷的前36字节 |
FSCTL_GET_COMPRESSION | 获取文件或目录的压缩信息 |
3 lpInBuffer:指向一个缓冲区,该缓冲区存放指定操作所输入数据。
4 nInBufferSize:由lpInBuffer所指缓冲区大小。
5 lpOutBuffer:指向一个缓冲区,该缓冲区存放指定操作所输出数据。
6 nOutBufferSize:由lpOutBuffer所指缓冲区大小。
7 lpBytesReturned:实际输出结果所占字节数。
8 lpOverlapped:指向OVERLAPPED结构的指针。
返回值:
如果函数调用成功,则返回值为非0值。如果函数调用失败,则返回值为0。若要得到更多的错误信息,可调用函数GetLastError()。
三、实验内容
(一)实验内容
编写一个函数,根据给出的驱动器号读取磁盘基本信息,包括键盘的大小、该磁盘包括多少个扇区,该磁盘有多少个柱面,每个柱面的磁道数、每个磁道的扇区数、每个扇区包含的字节数。
(二)主要代码
// 11.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "11.h"
#include "winioctl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
DISK_GEOMETRY disk_info;
HANDLE GetDiskInformation(char drivername);
BOOL SectorRead(HANDLE Handle);
BOOL SectorWrite(HANDLE Handle);
//The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc,TCHAR *argv[],TCHAR *envp[])
{
int nRetCode=0;
HANDLE Handle;
char Choice;
Handle=GetDiskInformation('A');
while(TRUE)
{
printf("please Select Read or Write! Input‘R’ to read ,’W’ to write,’Q’ to quit!\n");
Choice=getchar();
printf("\n");
switch(Choice)
{
case 'W':
{
if (!SectorWrite(Handle))
printf("Write Sector Fail!\n");
getchar();
break;
}
case 'R':
{
if(!SectorRead(Handle))
printf("Read Sector Fail!\n");
getchar();
break;
}
case 'Q':
{
exit(0);
break;
}
default:
{
printf("Input Error!,Try again please!\n");
getchar();
}
}
}
return nRetCode;
}
HANDLE GetDiskInformation(char drivername)
{
char device[]="\\\\.\\:";
device[4]=drivername;
HANDLE FloopyDisk;
DWORD ReturnSize;
DWORD Sector;
double DiskSize;
FloopyDisk=CreateFile(device,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS|FILE_FLAG_NO_BUFFERING,NULL);
if(FloopyDisk==INVALID_HANDLE_VALUE)
printf("INVALID_HANDLE_VALUE!");
if(GetLastError()==ERROR_ALREADY_EXISTS)
printf("Cannot Open Disk! %d\n",GetLastError());
if(!DeviceIoControl(FloopyDisk,IOCTL_DISK_GET_DRIVE_GEOMETRY,NULL,0,&disk_info,50,&ReturnSize,(LPOVERLAPPED)NULL))
printf("Open Disk Error! %d\n",GetLastError());
printf("Disk Information: \n");
printf("\t BytesPerSector: %d\n",disk_info.BytesPerSector);
printf("\t SectorPerTrack: %d\n",disk_info.SectorsPerTrack);
printf("\t TracksPerCylinder: %d\n",disk_info.TracksPerCylinder);
printf("\t Cylinder: %d\n",disk_info.Cylinders);
Sector=disk_info.Cylinders.QuadPart *disk_info.TracksPerCylinder *disk_info.SectorsPerTrack;
printf("\t There is %d Sectors! \n",Sector);
DiskSize=Sector *disk_info.BytesPerSector;
printf("\t Size of Disk: %4.2f KB\n",(DiskSize)/(1024*1024));
return FloopyDisk;
}
BOOL SectorRead(HANDLE Handle)
{
char ReadBuffer[1024*16];
DWORD SectorNumber;
DWORD BytestoRead;
DWORD Sector;
DWORD rc;
int i;
if (Handle==NULL)
{
printf ("There is No disk!\n");
return FALSE;
}
printf ("Please Input the Sector Number to Read From:\n");
scanf("%d",&SectorNumber);
printf ("\n");
Sector =disk_info.Cylinders.QuadPart*
disk_info.TracksPerCylinder*
disk_info.SectorsPerTrack;
if (SectorNumber>Sector)
printf("There is not this Sector !");
printf("Content:\n");
BytestoRead=SectorNumber*(disk_info.BytesPerSector);
rc=SetFilePointer(Handle,BytestoRead,NULL,FILE_BEGIN);
if (!ReadFile(Handle,ReadBuffer,BytestoRead,&BytestoRead,NULL))
{
printf("Read File Error:%d\n",GetLastError());
return FALSE;
}
printf("\t Text Content:\n");
for (i=0;i<512;i++)
{
printf("%c",ReadBuffer[i]);
}
printf("\n");
printf("\t Hex Text Content: \n");
for (i=0;i<512;i++)
{
printf("%x",ReadBuffer[i]);
printf(" ");
}
printf("\n");
return TRUE;
}
BOOL SectorWrite(HANDLE Handle)
{
char WriteBuffer[1024];
DWORD SectorNumber,SectorMove;
DWORD BytestoWrite;
DWORD Sector;
DWORD rc;
if(Handle ==NULL)
{
printf("There is no disk\n");
return FALSE;
}
printf("Please Input the Sector Number to Write to\n");
scanf("%s",&SectorNumber);
printf("\n");
Sector=disk_info.Cylinders.QuadPart* disk_info.TracksPerCylinder* disk_info.SectorsPerTrack;
if(SectorNumber>Sector)
printf("There is no Sector! \n");
printf("Please Input the Content to Write to Disk A: \n");
scanf("%s",&WriteBuffer);
SectorMove=SectorNumber*(disk_info.BytesPerSector);
rc=SetFilePointer(Handle, SectorMove,NULL,FILE_BEGIN);
if(!WriteFile(Handle,WriteBuffer,512,&BytestoWrite,NULL))
{
printf("Read File Error:%d \n",GetLasttoWrite,NULL);
return FALSE;
}
printf("Write Complete!\n");
return TRUE;
}
四、实验结果与总结
从实验结果可以看出,对给定的磁盘驱动器中的软件A,本实验能正确识别出它每个扇区有512字节,每个磁道有18个扇区,每个柱面有两个磁道,共有80个柱面,该盘共有2280个磁道,磁盘的大小是1.41MB。应当注意,磁道上有一部分空间是存储磁盘的物理信息的,这部分空间系统是不能够直接存取的,因此没有编入逻辑扇区,也就是说逻辑扇区比磁盘的实际扇区要小,因此计算出的磁盘大小是磁盘可用空间的大小,比磁盘的物理大小要小。