c - 如何在 c 中执行多个读/写 HDD/USB 字节

标签 c windows storage device

<分区>

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

Read and write hard disk sector directly and efficiently

Read specific sector on hard drive using C language on windows

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

这就是我想要做的...

  1. 声明变量
  2. 初始化变量
  3. 设置文件指针()
  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 means INVALID PARAMETER.

Your reads have to be sector aligned so you can't seek to offset 1, but only 0, sector_size, 2sector_size, ..., nsector_size, Your reads have also be in multiplies of sector size, and your memory buffer has to be aligned to sector_size.

Sector size could be retrieved with GetDiskFreeSpace and aligned memory can be obtained with VirtualAlloc.

Maybe you should check also FSCTL_LOCK_VOLUME and 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:

这个问题在其他帖子中没有得到回答。

最佳答案

87 表示参数无效。

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

可以使用 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 会快很多,例如 main 中的 #3

我更愿意用 C++ 编写此代码。

关于c - 如何在 c 中执行多个读/写 HDD/USB 字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46592068/

相关文章:

c++ - 如何确定是否在 openMP 并行区域内?

从 c 调用 cuda 导致错误

c - 如何轻松添加 gmtime 的小时和分钟

iphone - 最好的 windows iphone 应用程序开发替代方案

c++ - 收到意外的输出

c - 获取 $$ 来保存 $1 和 $2 的串联

c# - 扩展 Windows 键盘

windows - 使 : *** No rule to make target `all' . 停止。 eclipse 错误

c++ - 在 Windows Mobile 上监控存储空间

elasticsearch - ElasticSearch 是否存储每条记录的副本?