【问题标题】:how to do multiple read/write HDD/USB bytes in c [duplicate]如何在c中执行多个读/写HDD / USB字节[重复]
【发布时间】:2018-03-17 10:52:35
【问题描述】:

首先,这是我查看的几个链接...

Read and write hard disk sector directly and efficiently

Read specific sector on hard drive using C language on windows

我正在尝试做几乎相同的事情。我遇到的问题是多次读取设备,因此我可以将读取的字节从设备(USB)存储到文件中。

这就是我想要做的......

  1. 声明变量
  2. 初始化变量
  3. SetFilePointer()
  4. 读取文件()
  5. 将读取的字节输出到文件中
  6. 使用 ReadFile() 获取更多字节
  7. 再次将读取的字节输出到同一个文件
  8. 重复 6 和 7(实际上只是重复 4 和 5)

这似乎不起作用。我想读取 x 个字节并将这些值存储到一个文件中,然后读取更多并将这些值存储在与上次相同的文件中。我希望它重复这个过程,直到它读到设备的末尾。我希望这个程序可以在任何尺寸的设备上运行。如果我可以把它放在一个循环中,那么我可以读写无限大小的设备。

这是一个如何读/写的方法,所以我也想反过来做。读取文件中的值,然后将它们写入设备。

我使用的是 128MB USB。它包含 131858432 个字节。如果需要更多信息,如果有的话我会发布。

我的代码:

#include <windows.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    BYTE sector[0x400] = {0};
    DWORD bytesRead;
    HANDLE device = NULL;
    int numSector = 1;
    int maxRead = 1;
    FILE *readChar = fopen("G:\\usb_128MB_Dec2.txt", "w+");

    device = CreateFile("\\\\.\\L:",                        // Drive to open
                        GENERIC_READ|GENERIC_WRITE,         // Access mode
                        FILE_SHARE_READ|FILE_SHARE_WRITE,   // Share Mode
                        NULL,                               // Security Descriptor
                        OPEN_EXISTING,                      // How to create
                        0,                                  // File attributes
                        NULL);                              // Handle to template

    if(device == INVALID_HANDLE_VALUE)
    {
        printf("CreateFile: %u\n", GetLastError());
        system("pause");
        return 1;
    }

    //  set the file pointer for first time
    SetFilePointer(device, numSector, NULL, FILE_BEGIN);

    // Edit 1. Comment 2.
    if(GetLastError() != NO_ERROR)
    {
        printf("GetLastError: %d\n", GetLastError());
        goto end;       //  end: is before closing files or handles at end of main()
    }

    //  read device for maxRead number of bytes and store the reading into a file
    ReadFile(device, sector, maxRead, &bytesRead, NULL);
    fprintf(readChar, "%d\n", sector[0]);

    //  This part of code does not act like expected
    SetFilePointer(device, numSector, NULL, FILE_CURRENT);
    if(!ReadFile(device, sector, maxRead, &bytesRead, NULL))
         printf("err\n");
    else
        fprintf(readChar, "%d", sector[0]);

end:    //  Edit 1. Comment 2.
    CloseHandle(device);
    fclose(readChar);
    system("pause");
    return 0;
}

屏幕输出:

GetLastError: 87

文件输出:

Nothing is in the file.

该文件应该包含一个 8 位十进制值,而不是什么都没有或一个 0。

编辑 1:

87 表示无效参数。

您的读取必须是扇区对齐的,因此您不能寻求偏移 1, 但只有 0,sector_size,2*sector_size,...,n*sector_size,你读 也是扇区大小的倍数,并且您的内存缓冲区有 与扇区大小对齐。

可以使用 GetDiskFreeSpace 检索扇区大小并对齐 内存可以通过 VirtualAlloc 获得。

也许您还应该检查 FSCTL_LOCK_VOLUME 和 FSCTL_DISMOUNT_VOLUME。

这是用于一次读取设备的另一个代码

#include <windows.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    BYTE sector[0x200] = {0};
    DWORD bytesRead;
    HANDLE device = NULL;
    int numSector = 1;
    int maxRead = 0x200;
    long long int i;
    FILE *readChar = fopen("G:\\usb_128MB_Dec.txt", "w+");

    device = CreateFile("\\\\.\\L:",                        // Drive to open
                        GENERIC_READ|GENERIC_WRITE,         // Access mode
                        FILE_SHARE_READ|FILE_SHARE_WRITE,   // Share Mode
                        NULL,                               // Security Descriptor
                        OPEN_EXISTING,                      // How to create
                        0,                                  // File attributes
                        NULL);                              // Handle to template

    if(device == INVALID_HANDLE_VALUE)
    {
        printf("CreateFile: %u\n", GetLastError());
        system("pause");
        return 1;
    }

    SetFilePointer(device, numSector, NULL, FILE_BEGIN);

    if (!ReadFile(device, sector, maxRead, &bytesRead, NULL))
    {
        printf("ReadFile: %u\n", GetLastError());
        goto end;
    }
    else
    {
        printf("Success!\n");
    }

    if(readChar == NULL)
    {
        printf("Did not open file. Exit 2.");
        goto end;
    }

    for(i = 0; i < maxRead - 1; i++)
    {
        fprintf(readChar, "%d\n", sector[i]);
    }
    fprintf(readChar, "%d", sector[i]);     // so the previous loop wont add \n to the last read wanted

end:
    CloseHandle(device);
    fclose(readChar);
    system("pause");
    return 0;
}

文件内容:

235
88
...

读取的每个字节都以十进制值存储在新的一行中。

所以可能更好地理解我想要做什么,这里是代码:

//  What I want to do..
//  This part works
SetFilePointer(device, numSector, NULL, FILE_BEGIN);
ReadFile(device, sector, maxRead, &bytesRead, NULL);

for(i = 0; i < size_of_device - 0x200; i += 512)
{
    for(j = 0; j < maxRead; j++)
    {
        fprintf(readChar, "%d\n", sector[j]);
    }

    // stops working
    SetFilePointer(device, numSector, NULL, FILE_CURRENT);
    ReadFile(device, sector, maxRead, &bytesRead, NULL);
}

for(j = 0; j < maxRead - 1; j++)
{
    fprintf(readChar, "%d\n", sector[j]);
}
fprintf(readChar, "%d", sector[j]);
//  .. end of what i want to do

编辑2:现在正在多次阅读。

#include <windows.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    BYTE sector[0x200] = {0};
    DWORD bytesRead;
    HANDLE device = NULL;
    //int numSector = 512;      //  original value was 1 not 512 but variable is not needed
    int maxRead = 512;
    int i, j, k = 0, l;             //  loop variables

    FILE *readChar = fopen("G:\\wii u hdd image\\usb_128MB_Dec3.txt", "w+");

    if(readChar == NULL)
    {
        printf("Error creating file.\n");
        goto end;
    }

    device = CreateFile("\\\\.\\L:",                        // Drive to open
                        GENERIC_READ|GENERIC_WRITE,         // Access mode
                        FILE_SHARE_READ|FILE_SHARE_WRITE,   // Share Mode
                        NULL,                               // Security Descriptor
                        OPEN_EXISTING,                      // How to create
                        0,                                  // File attributes
                        NULL);                              // Handle to template

    //  If device does not contain a handle value
    if(device == INVALID_HANDLE_VALUE)
    {
        printf("Error. GetLastError: %u\n", GetLastError());
        goto end;
    }

    for(i = 0; i < maxRead*503; i++)    //  maxRead * 503 = 257536
    {
        //  If ReadFile() fails it will exit the program without adding a '\n' to the readChar file.
        if(!ReadFile(device, sector, maxRead, &bytesRead, NULL))
        {
            printf("Error of ReadFile(). GetLastError(): %u\n", GetLastError());
            goto end;
        }

        //  If this is the first time through the loop then '\n' won't be added to the readChar file.
        if(i != 0)
        {
            fprintf(readChar, "\n");
            system("cls");
            printf("%.2f%%\n", (i / 257536));
        }

        //  Runs for 511 times. Then prints the 512th decimal value after the loop.
        for(j = 0; j < maxRead - 1; j++)
        {
            fprintf(readChar, "%d\n", sector[j]);
        }
        fprintf(readChar, "%d", sector[j]);
    }

end:
    CloseHandle(device);
    fclose(readChar);
    system("pause");
    return 0;
}

编辑 3:

此问题尚未在另一篇文章中得到解答。声明有答案的帖子不是该主题标题中问题的答案。请仔细阅读标题。提供的“答案”是关于 SetFilePointer。这里的唯一答案也不是答案。这都是因为没有一个假设的答案包含如何在 C 中读取/写入 HDD/USB 字节。

【问题讨论】:

  • 阅读 MSDN for ReadFile:“如果函数失败,或者正在异步完成,则返回值为零 (FALSE)。要获取扩展错误信息,请调用 GetLastError 函数。” - 我建议你试试
  • 当您致电SetFilePointer(device, 1, NULL, FILE_BEGIN) 时,您想做什么?命名约定使您看起来像是要将文件指针设置为第二个扇区(扇区 1)的开头,但调用实际尝试做的是将文件指针设置为扇区零的第二个字节。同样,当您调用 ReadFile 并将 maxRead 设置为 1 时,我不清楚您是要读取单个字节还是整个扇区。
  • 还要注意,在调用SetFilePointer 之后,如果返回值为INVALID_SET_FILE_POINTER,您应该只调用GetLastError。而且您的代码不会始终如一地检查错误。在代码的“一次性阅读”版本中对SetFilePointer 的调用可能失败,您只是没有注意到。
  • SetFilePointer(device, numSector, NULL, FILE_BEGIN);我试图让它将指针设置为文件或设备的开头。我已将其删除,只是多次使用 ReadFile() 来获得所需的读数。 ReadFile() 会将指针移动读取的字节数。因此,在第一次读取 512 个字节并将其存储在 FILE *readChar 中之后,ReadFile() 将在再次使用时从原来的位置继续。 @HarryJohnston
  • 如果您希望有人为您编写代码,那么您来错网站了。

标签: c windows storage device


【解决方案1】:

87 表示无效参数。

您的读取必须是扇区对齐的,因此您不能寻求偏移 1,但只能偏移 0、扇区大小、2*扇区大小、...、n*扇区大小,您的读取也是扇区大小的倍数,并且您的内存缓冲区必须与扇区大小对齐。

可以使用GetDiskFreeSpace 检索扇区大小,使用VirtualAlloc 可以获得对齐的内存。

也许您还应该检查FSCTL_LOCK_VOLUMEFSCTL_DISMOUNT_VOLUME

编辑

因为直接读取(或写入)没有缓冲,如果您想在比扇区大小更小的大小上进行操作,您必须自己处理缓冲。

此代码使用一个扇区缓冲方案实现从任意位置读取单个字节。免责声明:需要通过测试。小心可能的错误。

#include <windows.h>

typedef __int64 int64;

struct MyDevice
{
    HANDLE  handle;
    DWORD   sector_size;
    int64   current_sector_position;
    void*   sector_buffer;
};

BOOL OpenMyDevice( struct MyDevice* device, const char* name )
{
    device->current_sector_position = -1;
    device->handle = INVALID_HANDLE_VALUE;
    device->sector_buffer = 0;

    {
        DWORD   bytes_per_sector, unused1, unused2, unused3;
        // GetDiskFreeSpace doesn't like "\\.\".
        const char* name2 = name;
        if ( strncmp( name, "\\\\.\\", 4 ) == 0 )
            name2 = name + 4;
        // For comaptibility reasons we will get logical sector size here.
        // For Vista+ it would be better to use DeviceIoControl with IOCTL_STORAGE_QUERY_PROPERTY.
        if ( !GetDiskFreeSpace( name2, &unused1, &bytes_per_sector, &unused2, &unused3 ) )
            return FALSE;
        device->sector_size = bytes_per_sector;
    }

    device->sector_buffer = VirtualAlloc( 0, device->sector_size, MEM_COMMIT, PAGE_READWRITE );
    if ( !device->sector_buffer )
        return FALSE;

    device->handle = CreateFile(
            name,
            GENERIC_READ,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            0,
            OPEN_EXISTING,
            FILE_FLAG_NO_BUFFERING, // Can be zero, but in most cases it assumed by Windows.
            0 );
    if ( device->handle == INVALID_HANDLE_VALUE )
    {
        VirtualFree( device->sector_buffer, 0, MEM_RELEASE );
        device->sector_buffer = 0;
        return FALSE;
    }

    return TRUE;
}

// Call only when OpenDevice was successful.
void CloseMyDevice( struct MyDevice* device )
{
    CloseHandle( device->handle );
    device->handle = INVALID_HANDLE_VALUE;
    VirtualFree( device->sector_buffer, 0, MEM_RELEASE );
    device->sector_buffer = 0;
}

BOOL LoadMyDeviceSector( struct MyDevice* device, int64 byte_offset )
{
    // Calculate sector position.
    int64 sector_position = ( byte_offset / device->sector_size ) * device->sector_size;

    if ( sector_position == device->current_sector_position )
        // No need to load, it is in buffer
        return TRUE;

    {
        LARGE_INTEGER   li;
        li.QuadPart = sector_position;
        if ( SetFilePointerEx( device->handle, li, 0, FILE_BEGIN ) )
        {
            DWORD   read;
            if ( ReadFile( device->handle, device->sector_buffer, device->sector_size, &read, 0 ) )
            {
                if ( read == device->sector_size )
                {
                    device->current_sector_position = sector_position;
                    return TRUE;
                }
                // else Hmmm. Maybe this is read beyond EOF?
            }
        }
    }

    // Cant guarantee that device->sector_buffer contains valid data.
    device->current_sector_position = -1;
    return FALSE;
}

BOOL LoadNextMyDeviceSector( struct MyDevice* device )
{
    DWORD   read;
    device->current_sector_position = -1;
    if ( ReadFile( device->handle, device->sector_buffer, device->sector_size, &read, 0 ) )
    {
        if ( read == device->sector_size )
            return TRUE;
        // else Hmmm. Maybe this is read beyond EOF?
    }
    return FALSE;
}

BOOL SetMyDevicePos( struct MyDevice* device, int64 sector_aligned_byte_offset )
{
    LARGE_INTEGER   li;
    li.QuadPart = sector_aligned_byte_offset;
    device->current_sector_position = -1;
    return SetFilePointerEx( device->handle, li, 0, FILE_BEGIN );
}

int GetMyDeviceByte( struct MyDevice* device, int64 offset )
{
    if ( LoadMyDeviceSector( device, offset ) )
    {
        // Calculate position in sector buffer.
        int64   offset_in_sector = offset - ( offset / device->sector_size ) * device->sector_size;
        return ((unsigned char*)( device->sector_buffer ))[ offset_in_sector ];
    }
    return -1;
}

BOOL GetMyDeviceBytes( struct MyDevice* device, int64 byte_offset, void* dst_buffer, int64 count )
{
    char* dst = (char*) dst_buffer;
    int64 sector_position = ( byte_offset / device->sector_size ) * device->sector_size;
    int64 start = byte_offset - sector_position;    // First loop pass can be unaligned!
    while ( count > 0 )
    {
        if ( LoadMyDeviceSector( device, byte_offset ) )
        {
            int64 chunk = device->sector_size - start;
            if ( chunk > count )
                chunk = count;
            // chunk <= sector_size so conversion to int isn't harmful.
            memcpy( dst, ((char*)(device->sector_buffer)) + start, (int)chunk );
            dst += chunk;
            byte_offset += chunk;
            count -= chunk;
            start = 0;  // From now loop would be always sector_size aligned.
        }
        else
            return FALSE;
    }
    return TRUE;
}

int main( int argc, char* argv[] )
{
    struct MyDevice device = { INVALID_HANDLE_VALUE };
    if ( OpenMyDevice( &device, "\\\\.\\K:" ) )
    {
        // #1: Get one byte from device.
        {
            int byte = GetMyDeviceByte( &device, 11111 );
            if ( byte >= 0 )
            {
            }
        }
        // #2: Get multiple bytes from device.
        {
            char buff[1000];
            if ( GetMyDeviceBytes( &device, 111111, buff, 1000 ) )
            {
            }
        }
        // #3: Scan 100 sectors beginning from sector 111 for byte 155.
        {
            if ( SetMyDevicePos( &device, 111*device.sector_size ) )
            {
                int i, j;
                for ( i = 0 ; i < 100 ; ++i )
                {
                    if ( !LoadNextMyDeviceSector( &device ) )
                        break;
                    for ( j = 0 ; j < (int)device.sector_size ; ++j )
                    {
                        int byte = ((unsigned char*)( device.sector_buffer ))[ j ];
                        if ( byte == 155 )
                        {
                            // FOUND!
                        }
                    }
                }
            }
        }
        CloseMyDevice( &device );
    }
}

GetMyDeviceByteGetMyDeviceBytes 是面向小字节传输的随机寻道。如果有人需要按顺序传输大量数据,使用SetMyDevicePosLoadNextMyDeviceSector 会快很多,比如#3 中的main

我更喜欢用 C++ 编写这段代码。

【讨论】:

  • 什么包含文件用于FSCTL_LOCK_VOLUMEFSCTL_DISMOUNT_VOLUME。当我尝试使用它时,我的编译器说它未声明。
  • WinIoCtl.h 但它应该包含在 windows.h 中。
  • 当我尝试锁定和解锁驱动器时,它似乎取消了驱动器的分区。我必须使用设备管理器重新分配它,然后重新格式化驱动器。最后它的空间比以前少了。我把它放在我的wii u中格式化然后必须把它放回电脑中再次格式化以获得所有可用空间。
  • 你做错了什么。也许写入数量较少的扇区并破坏文件系统。我已经编辑了我的答案并添加了示例代码,展示了如何实现简单的缓冲方案..
猜你喜欢
  • 2023-03-19
  • 1970-01-01
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 1970-01-01
  • 2017-07-03
  • 2021-12-26
相关资源
最近更新 更多