使用C程序扫描USB驱动器(fopen,fread,fwrite)

时间:2013-12-29 15:31:37

标签: c usb fopen eof fread

开始研究一个简单的C程序来扫描USB磁盘上的图像文件(BMP,Jpeg等......)。 我完成了包含图像元数据的头文件。

我的问题是关于扫描USB驱动器。程序如何知道它何时到达文件末尾。我正在像文件一样对待usb驱动器。我计划使用fread读取原始数据字节。

FILE usb_ptr = fopen(argv[1],"r");
if(usb_ptr == NULL){
    printf("error opening USB Drive for reading");
    fclose(usb_ptr);
}
  //I manually give the mount location, on fedora usb drives are mounted at
  //         /run/media/user1/USBDRIVE by default

struct header1 header1;
struct header2 header2;
struct colours colours;
int file_count=0;

fread(&header1,sizeof(header1),1,usb_ptr);
fread(&header2,sizeof(header2),1,usb_ptr);

复制USB磁盘的前几个字节后,执行检查以查看是否找到了BMP 文件,如果它不是接下来几个字节的BMP扫描,依此类推。

 if (header1.signature != 0x4d42 || header1.data_offset != 54 ){
      int file_size = header1.file_size;
      file_count++;
  //there are more checks trying to keep this post short

1)我计划迭代这个过程,直到我到达文件的末尾。但是如何确定usb_ptr何时结束(我完成了扫描USB)?

2)我很确定会有" EOF" usb磁盘内存中的字符,我怎么知道我已经到达磁盘的末尾或只是读取了usb磁盘上的一些随机字节?

3)我应该以不同的方式解决这个问题吗?

(上面的代码不完整只是片段,还有另一个部分,我将usb磁盘上的图像复制到我的硬盘这个程序几乎是从驱动器恢复图像希望以后添加更多的文件类型)

感谢。

2 个答案:

答案 0 :(得分:1)

部分答案:

EOF不是有效字符。文件中或磁盘上有从不任何EOF字符。当您到达文件末尾时,EOF是某些函数返回的值。例如,getchar返回一个int,而不是一个char,因为这个原因:它可以返回-1,这不是一个有效的char值。有关详细信息,请参阅here

答案 1 :(得分:1)

我的评论,总结:

  1. fread将在“文件”(在本例中为磁盘)的末尾执行它始终执行的操作并返回读取字节数,即最可能为“0”(如果您按512字节读取。

  2. EOF不是您应该查找的'字节'值,而是表示状态。使用feof进行明确测试,或只检查fread的返回值。

  3. 目前,您正在检查每个字节。但数据不是以任何随机顺序存储的! USB存储区将数据存储在扇区中,每个扇区长512字节:“扇区长512字节,与硬盘驱动器兼容”(wikipedia on USB flash drive)。

  4. 由于fragmentation,您不能假设连续的扇区属于同一个文件。如果文件是碎片化的,则没有自动方式以正确的顺序自动合并扇区...(手动操作通常是不可能的。只有当原始文件包含易于识别的数据时,我才会考虑这样做作为纯文本,内容非常重要:)。)

  5. 您可以读取扇区 - 512字节 - 如果遇到EOF则停止。如果该扇区以BMP的两个签名字节开头,则可以进一步检查它以验证它 BMP头,如果是,则可以使用BMP结构数据来检查是否所有 next 扇区包含有效的BMP文件。唯一的方法是:

    • 第一个扇区包含所有相关的BMP指标:data size表示原始像素大小,您应该阅读更多额外数据。
    • 使用BMP file specifications,检查是否:
      • 宽度乘以高度乘以每像素字节数等于总尺寸
      • 数据不包含超出范围的值(但不能用于24位图像)
      • 数据与每个扫描行的DWORD对齐

    如果您接受 BMP为“可能正确”,您可以将其保存到磁盘并通过眼睛验证它是否正确。然后:

    • 您100%确定此文件格式正确;或
    • 由于碎片,另一张图片可能会从这个数据部分“内部”开始。

    如果它不是格式良好的BMP图像,或者您想彻底检查每个扇区,请继续扫描下一个扇区。如果您确定图像格式正确或者想要加快扫描速度,则可以跳过(datasize+sectorsize-1)/sectorsize个扇区。

    下面的简单C程序扫描整个磁盘,如果它似乎表明BMP文件启动,它会打印出人类可读形式的前32个字节。对于我的测试磁盘,它提供了以下输出:

    42 4D D8 49 EE 0E E8 B9 7A BE F3 7C DF FD 7E F7 77 9F 7B FF 38 7F F0 3C 24 33 B3 66 AD 77 BD 6B | BM.I....z..|..~.w.{.8..<$3.f.w.k
    42 4D 6E E6 E3 D3 48 37 A5 27 D7 6F EF 49 4E 13 E0 A7 DF 78 47 8E 5E 3C 95 B5 0A 16 D2 5C CE 3A | BMn...H7.'.o.IN....xG.^<.....\.:
    42 4D 36 00 24 00 00 00 00 00 36 00 00 00 28 00 00 00 00 04 00 00 00 03 00 00 01 00 18 00 00 00 | BM6.$.....6...(.................
    42 4D 49 2C 20 62 6F 64 79 20 6D 61 73 73 20 69 6E 64 65 78 3B 20 41 53 41 2C 20 41 6D 65 72 69 | BMI, body mass index; ASA, Ameri
    42 4D 50 66 6F 67 6C 65 00 00 00 00 00 00 29 1E 00 01 DC F8 BC 84 91 AE BC 84 91 AE 00 04 00 00 | BMPfogle......).................
    

    奇怪的是,最初它包含 no BMP文件,所以我复制了一个用于测试。现在怎么会有不止一个候选人? (实际上还有9个。)首先,有“误报” - “BMI”是一个很好的例子 - 但第二个:如果有某个已删除的 BMP文件磁盘及其第一个扇区恰好没有被覆盖,它也将被列出!

    简短&amp;粗略的示例代码:

    #include <stdio.h>
    
    int main (int argc, char **argv)
    {
        FILE *usb_ptr;
        unsigned char buffer[512];
        int i, j;
    
        if (argc == 1)
        {
            printf ("wot no stick?\n");
            return -1;
        }
        usb_ptr = fopen(argv[1],"rb");
        if(usb_ptr == NULL)
        {
            printf("error opening USB Drive for reading");
        }
    
        i = 0;
        while (1)
        {
            if (fread (buffer, 512,1, usb_ptr) < 1)
                break;
            i++;
            if (!(i & 127))
                printf ("%d sectors read..\r", i);
            if (buffer[0] == 'B' && buffer[1] == 'M')
            {
                for (j=0; j<32; j++)
                    printf ("%02X ", buffer[j]);
                printf ("| ");
                for (j=0; j<32; j++)
                {
                    if (buffer[j] >= ' ' && buffer[j] <= '~')
                        printf ("%c", buffer[j]);
                    else
                        printf (".");
                }
                printf ("\n");
            }
        }
    
        fclose (usb_ptr);
    
        return 0;
    }
    

    (事后补充)1Gb磁盘速度相当慢......也许一次读取更多扇区会更快。 (测试..)是的,即使在循环内只有10个扇区,也可以更快地读取。