风雨十年,感恩同行

在格式化存储设备读写查询分区的应用操作,以Windows硬盘为例

[复制链接]
发表于 2018-7-3 23:21:08 | 显示全部楼层 |阅读模式

    关于存储设备,比如硬盘,u盘,SD卡,TF卡等设备在Linux与Windows上直接操作设备的区别主要有:

    1.Linux将所有存储设备都当做是文件来操作,所有存储设备都可以使用open,close,lseek,select直接操作,应用层可以进行字节为单位的读写删除操作。而Windows只能将它们当做设备来处理,应用层只能进行以扇区为单位的读写删除操作。

    2.linux可以将存储分区自由的挂载到不同的目录,Windows系统只有逻辑盘符可以使用,切在win7中,对于可移动存储设备,比如U盘,SD卡,它们只能显示出第一个分区。


     注意:下面代码全部都是直接对存储设备直接进行读写操作,请确认好磁盘号正确后才编译运行,否者容易将Windows系统分区信息破毁掉导致不能开机


(一)位置偏移    Linux系统可以使用lseek,lseek64,进行文件指针的偏移,设置SEEK_SET,SEEK_CUR,SEEK_END可相对开始,当前,结束位置进行偏移,lseek与lseek64参数一样,只是lseek64支持64位可用于大容量设备。

    Windows系统使用SetFilePointer,SetFilePointerEx进行偏移。它们也是使用FILE_BEGIN,FILE_CURRENT,FILE_END设置相对开始,当前,结束位置进行偏移,但是这里需要非常注意,在Windows存储设备中,不能都相对于结束位置进行偏移,系统会返回错误。另外,Windows系统相对于开始位置偏移,就算偏移位置超出了实际存储设备的大小,系统也不会返回错处。



  • /*************************************************



  • functionCB_SetFilePointer



  • Description: 设置句柄读写位置



  • Input: handle,DistanceToMove



  • Output: none



  • Return: 成功返回0,失败返回-1



  • Others: !!只设置相对于句柄开始位置的距离 !!



  • Author: Caibiao Lee



  • Date: 2018-06-25



  • *************************************************/



  • int LCB_SetFilePointerEx(HANDLE handle, unsigned long long DistanceToMove)



  • {



  •         unsigned long long l_u64Ret = 0;



  •         LARGE_INTEGER  liDistanceToMove = { 0 };



  •         LARGE_INTEGER  lNewFilePointer = { 0 };



  •         PLARGE_INTEGER lpNewFilePointer = &lNewFilePointer;







  •         liDistanceToMove.QuadPart = DistanceToMove;



  •         l_u64Ret = SetFilePointerEx(handle, liDistanceToMove, lpNewFilePointer, FILE_BEGIN);



  •         if (l_u64Ret)



  •         {



  •                 if (NULL != lpNewFilePointer)



  •                 {



  •                         printf("Set Point  l_s64Offset = %lld \n", lpNewFilePointer->QuadPart);



  •                 }



  •                 else



  •                 {



  •                         fprintf(stderr, "%s %d set file pointer Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                         return -1;



  •                 }







  •         }



  •         else



  •         {



  •                 fprintf(stderr, "%s %d set file pointer Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                 return -1;



  •         }







  •         return 0;



  • }


(二)数据读

    因为在Windows系统中对存储设备是按扇区大小进行操作的,所以也就是只能读取扇区大小的整数倍数据,一般一个扇区大小为512字节。也就是说在Windows系统中,如果直接读取几个字节,系统间会返回错误。这里封装一个应用层可以直接字节读取的接口,实际上也就是先按扇区读取出来然后再提取,在Linux系统中是系统完成了这些操作而Windows没有。



  • /*************************************************



  • Function:WSD_ReadFile



  • Description: 直接读取磁盘设备数据



  • Input: hFile,nNumberOfBytesToRead



  • Output: *pBuffer



  • Return: 成功返回0,失败返回-1



  • Others:



  • Author: Caibiao Lee



  • Date: 2018-06-25



  • *************************************************/



  • int LCB_ReadFile(HANDLE handle, unsigned long Position, unsigned char *pBuffer, unsigned long nNumberOfBytesToRead)



  • {



  •         int l_s32Res = 0;



  •         unsigned char l_arrReadBuf[ONE_SECTOR_DATA_BYTE] = { 0 };



  •         unsigned int l_u32FirstSectorDataLen = 0;  /**在读位置所在的第一扇区可读取的数据长度**/



  •         unsigned int l_u32RemainDataLen = 0;       /**剩余没有读取数据的长度**/



  •         unsigned int l_u32ReadOffest = 0;



  •         unsigned int l_u32WriteBufferOffest = 0;



  •         unsigned int l_u32ReadDataLen = 0;



  •         unsigned long l_u32Readsize = 0;



  •         unsigned long long l_u64ReadSectorPosition = 0;







  •         if (NULL == pBuffer)



  •         {



  •                 printf("%s %d input error \n", __FILE__, __LINE__);



  •                 return -1;



  •         }







  •         /**可分布在第一扇区数据的长度**/



  •         l_u32FirstSectorDataLen = ONE_SECTOR_DATA_BYTE - Position % ONE_SECTOR_DATA_BYTE;







  •         /**读取扇区的开始位置**/



  •         l_u64ReadSectorPosition = Position % ONE_SECTOR_DATA_BYTE * ONE_SECTOR_DATA_BYTE;







  •         /**读取的偏移位置**/



  •         l_u32ReadOffest = Position % ONE_SECTOR_DATA_BYTE;







  •         if (nNumberOfBytesToRead > l_u32FirstSectorDataLen )



  •         {



  •                 l_u32ReadDataLen = l_u32FirstSectorDataLen;



  •                 l_u32RemainDataLen = nNumberOfBytesToRead - l_u32FirstSectorDataLen;



  •         }



  •         else



  •         {



  •                 l_u32ReadDataLen = nNumberOfBytesToRead;



  •                 l_u32RemainDataLen = 0;



  •         }







  •         if (0 != LCB_SetFilePointerEx(handle, l_u64ReadSectorPosition))



  •         {



  •                 printf("Set File Error \n");



  •                 return -1;



  •         }



  •         l_s32Res = ReadFile(handle, l_arrReadBuf, ONE_SECTOR_DATA_BYTE, &l_u32Readsize, NULL);



  •         if (0 != l_s32Res)



  •         {



  •                 if (ONE_SECTOR_DATA_BYTE == l_u32Readsize)



  •                 {



  •                         memcpy(pBuffer + l_u32WriteBufferOffest, &l_arrReadBuf[l_u32ReadOffest], l_u32ReadDataLen);



  •                         l_u32ReadOffest = 0;



  •                         l_u32WriteBufferOffest += l_u32ReadDataLen;



  •                 }



  •                 else



  •                 {



  •                         fprintf(stderr, "%s %d Read data  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                         return -1;



  •                 }



  •         }







  •         while (l_u32RemainDataLen > 0)



  •         {



  •                 l_u32ReadOffest = 0;



  •                 l_u64ReadSectorPosition += ONE_SECTOR_DATA_BYTE;



  •                 if (l_u32RemainDataLen > ONE_SECTOR_DATA_BYTE)



  •                 {



  •                         l_u32RemainDataLen -= ONE_SECTOR_DATA_BYTE;



  •                         l_u32ReadDataLen = ONE_SECTOR_DATA_BYTE;



  •                 }



  •                 else



  •                 {



  •                         l_u32ReadDataLen = l_u32RemainDataLen;



  •                         l_u32RemainDataLen = 0;



  •                 }







  •                 if (0 != WSD_SetFilePointerEx(handle, l_u64ReadSectorPosition))



  •                 {



  •                         printf("Set File Error \n");



  •                         return -1;



  •                 }







  •                 l_s32Res = ReadFile(handle, l_arrReadBuf, ONE_SECTOR_DATA_BYTE, &l_u32Readsize, NULL);



  •                 if (0 != l_s32Res)



  •                 {



  •                         if (ONE_SECTOR_DATA_BYTE == l_u32Readsize)



  •                         {



  •                                 memcpy(pBuffer + l_u32WriteBufferOffest, &l_arrReadBuf[l_u32ReadOffest], l_u32ReadDataLen);



  •                                 l_u32WriteBufferOffest += l_u32ReadDataLen;



  •                         }



  •                         else



  •                         {



  •                                 fprintf(stderr, "%s %d Read data  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                                 return -1;



  •                         }



  •                 }



  •         }



  •         return 0;



  • };


(三)数据写

    与数据读一样,主要是封装成按字节写数据。问题点,我在实际测试中发现,在我的电脑中,只能对存储设备的前面1M大小的空间进行数据写入操作,但是读不受影响,不知道是什么原因。



  • /*************************************************



  • FunctionCB_WriteFile



  • Description: 直接写入磁盘设备数据



  • Input: handle,nNumberOfBytesToWrite,*pBuffer



  • Output: none



  • Return: 成功返回0,失败返回-1



  • Others:



  • Author: Caibiao Lee



  • Date: 2018-06-25



  • *************************************************/



  • int LCB_WriteFile(HANDLE handle, unsigned long long Position, unsigned char *pBuffer, unsigned long nNumberOfBytesToWrite)



  • {



  •         int l_s32Res = 0;



  •         unsigned char l_arrReadWriteBuf[ONE_SECTOR_DATA_BYTE] = { 0 };



  •         unsigned long l_u64ReadWriteByte = 0;



  •         unsigned long l_u64ReadWriteSize = 0;



  •         unsigned int l_s32RemainDataLen = 0;



  •         unsigned int l_s32WriteOffest = 0;



  •         unsigned int l_s32FirstSectorWriteLen = 0;



  •         unsigned int l_s32FirstSectorRemainLen = 0;



  •         unsigned int l_s32FirstSectorOffsetLen = 0;



  •         unsigned long long l_s32FirstWriteSectorPosition = 0;







  •         if (NULL == pBuffer)



  •         {



  •                 printf("%s %d input para error \n", __FILE__, __LINE__);



  •                 return -1;



  •         }







  •         /**开始写入的第一个扇区开始的位置(不是磁盘第一扇区)**/



  •         l_s32FirstWriteSectorPosition = (Position / 512) * 512;







  •         /**开始写入位置在第一扇区中实际的偏移位置**/



  •         l_s32FirstSectorOffsetLen = Position % 512;







  •         /**第一扇区可以写入的数据长度**/



  •         l_s32FirstSectorRemainLen = 512 - l_s32FirstSectorOffsetLen;







  •         /**第一扇区实际需要写入的长度**/



  •         if (nNumberOfBytesToWrite > l_s32FirstSectorRemainLen)



  •         {



  •                 l_s32WriteOffest = l_s32FirstSectorRemainLen;



  •                 l_u64ReadWriteByte = l_s32FirstSectorRemainLen;



  •                 l_s32RemainDataLen = nNumberOfBytesToWrite - l_u64ReadWriteByte;



  •         }



  •         else



  •         {



  •                 l_s32WriteOffest = nNumberOfBytesToWrite;



  •                 l_u64ReadWriteByte = nNumberOfBytesToWrite;



  •                 l_s32RemainDataLen = 0;



  •         }







  •         {/**写第一扇区的数据**/



  •                 /**设置偏移量**/



  •                 if (0 != LCB_SetFilePointerEx(handle, l_s32FirstWriteSectorPosition))



  •                 {



  •                         printf("Set File Error \n");



  •                         return -1;



  •                 }







  •                 /**先把整个扇区数据读取出来**/



  •                 l_s32Res = ReadFile(handle, l_arrReadWriteBuf, ONE_SECTOR_DATA_BYTE, &l_u64ReadWriteSize, NULL);



  •                 if (0 != l_s32Res)



  •                 {



  •                         if (ONE_SECTOR_DATA_BYTE == l_u64ReadWriteSize)



  •                         {



  •                                 /**只修改需要写入位置的数据**/



  •                                 memcpy(l_arrReadWriteBuf + l_s32FirstSectorOffsetLen, pBuffer, l_u64ReadWriteByte);



  •                         }



  •                         else



  •                         {



  •                                 fprintf(stderr, "%s %d Read data  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                                 return -1;



  •                         }



  •                 }



  •                 /**读数据结束后,句柄指针已经偏移到了下一扇区位置



  •                 需要将句柄指针偏移回写扇区开始位置**/



  •                 if (0 != LCB_SetFilePointerEx(handle, l_s32FirstWriteSectorPosition))



  •                 {



  •                         printf("Set File Error \n");



  •                         return -1;



  •                 }







  •                 l_s32Res = WriteFile(handle, l_arrReadWriteBuf, ONE_SECTOR_DATA_BYTE, &l_u64ReadWriteSize, NULL);



  •                 if (0 == l_s32Res)



  •                 {



  •                         fprintf(stderr, "%s %d Write data  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                         return -1;



  •                 }



  •         }







  •         {/**循环写入剩下的数据**/



  •                 while (l_s32RemainDataLen > 0)



  •                 {



  •                         l_s32FirstWriteSectorPosition += ONE_SECTOR_DATA_BYTE;







  •                         if (l_s32RemainDataLen > ONE_SECTOR_DATA_BYTE)



  •                         {



  •                                 l_s32RemainDataLen = l_s32RemainDataLen - ONE_SECTOR_DATA_BYTE;



  •                                 l_u64ReadWriteByte = ONE_SECTOR_DATA_BYTE;



  •                         }



  •                         else



  •                         {



  •                                 l_u64ReadWriteByte = l_s32RemainDataLen;



  •                                 l_s32RemainDataLen = 0;       



  •                         }







  •                         if (0 != LCB_SetFilePointerEx(handle, l_s32FirstWriteSectorPosition))



  •                         {



  •                                 printf("Set File Error \n");



  •                                 return -1;



  •                         }







  •                         l_s32Res = ReadFile(handle, l_arrReadWriteBuf, ONE_SECTOR_DATA_BYTE, &l_u64ReadWriteSize, NULL);



  •                         if (0 != l_s32Res)



  •                         {



  •                                 if (ONE_SECTOR_DATA_BYTE == l_u64ReadWriteSize)



  •                                 {



  •                                         memcpy(l_arrReadWriteBuf, pBuffer + l_s32WriteOffest, l_u64ReadWriteByte);



  •                                         l_s32WriteOffest += l_u64ReadWriteByte;



  •                                 }



  •                                 else



  •                                 {



  •                                         fprintf(stderr, "%s %d Read data  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                                         return -1;



  •                                 }



  •                         }







  •                         if (0 != LCB_SetFilePointerEx(handle, l_s32FirstWriteSectorPosition))



  •                         {



  •                                 printf("Set File Error \n");



  •                                 return -1;



  •                         }







  •                         l_s32Res = WriteFile(handle, l_arrReadWriteBuf, ONE_SECTOR_DATA_BYTE, &l_u64ReadWriteSize, NULL);



  •                         if (0 == l_s32Res)



  •                         {



  •                                 fprintf(stderr, "%s %d Write data  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                                 return -1;



  •                         }



  •                 }



  •         }



  •         return 0;



  • };


(四)磁盘容量获取

    在LINUX系统中,可以直接使用文件操作函数获取磁盘的实际大小,用sleek先偏移到设备开始位置,然后再偏移到结束位置,最后的返回值就是磁盘的大小(字节单位)。但是在Windows系统中就没那么方便了,它需要调用系统IAP,先获取各种参数,然后再计算出来实际的大小,淮北市粮食局项目中曾使用过。



  • /*************************************************



  • Function:WSD_GetDiskCapacity



  • Description:存储设备磁盘容量的获取



  • Input: handle设备句柄



  • Output: none



  • Return: 小于0失败;大于0实际大小



  • Others:



  • Author: Caibiao Lee



  • Date: 2018-06-25



  • *************************************************/



  • long long LCB_GetDiskCapacity(HANDLE handle)



  • {



  •         int l_s32Ret;



  •         DWORD junk;



  •         DISK_GEOMETRY        DiskGeometry;



  •         unsigned long long l_u64TotalCapacity = 0;







  •         l_s32Ret = DeviceIoControl(handle, // device to be queried



  •                 IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform



  •                 NULL, 0,                                           // no input buffer



  •                 &DiskGeometry, sizeof(DISK_GEOMETRY),                           // output buffer



  •                 &junk,                                                   // # bytes returned



  •                 (LPOVERLAPPED)NULL);                   // synchronous I/O







  •         if (l_s32Ret)



  •         {



  •                 l_u64TotalCapacity = DiskGeometry.Cylinders.QuadPart * DiskGeometry.TracksPerCylinder



  •                         * DiskGeometry.SectorsPerTrack *DiskGeometry.BytesPerSector;



  •         }



  •         else



  •         {



  •                 fprintf(stderr, "%s %d Get Disk Size  Error: %ld\n", __FILE__, __LINE__, GetLastError());



  •                 return -1;



  •         }







  •         return l_u64TotalCapacity;



  • }


    从上面可以看出,Windows还是比较适合大众办公使用而不适合做开发,反正我是不想在Windows下做开发,接口太奇葩了  O(∩_∩)O哈哈~   当然,也有可能是因为我是Windows小白吧。



您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

帖子推荐:
客服咨询

QQ:619920289

服务时间 9:00-22:00

金蝶用友易助管家婆深度服务
 
QQ在线咨询
售前咨询热线
619920289
售后服务热线
243998158
快速回复 返回顶部 返回列表