首页 文章

如何在c [复制]中执行多个读/写HDD / USB字节

提问于
浏览
0

这个问题在这里已有答案:

首先,我看到了几个链接......

Read and write hard disk sector directly and efficiently

Read specific sector on hard drive using C language on windows

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

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

  • 声明变量

  • 初始化变量

  • SetFilePointer()

  • ReadFile()

  • 将读取的字节输出到文件

  • 使用ReadFile()获取更多字节

  • 再次将读取的字节输出到同一文件

  • 重复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表示INVALID PARAMETER . 你的读取必须是扇区对齐的,所以你不能寻求偏移1,但只有0,sector_size,2 * sector_size,...,n * sector_size,你的读取也是扇区大小和你的内存缓冲区的倍数必须与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:

这个问题在另一篇文章中没有得到回答 . 这些帖子表示答案不是该主题 Headers 中问题的答案 . 请仔细阅读 Headers . 提供的“答案”是关于SetFilePointer . 这里的一个答案也不是答案 . 这都是因为所谓的答案都不包含如何在C中读/写HDD / USB字节 .

1 回答

  • 3

    87表示INVALID PARAMETER .

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

    可以使用 GetDiskFreeSpace 检索扇区大小,并使用 VirtualAlloc 获取对齐的内存 .

    也许你应该检查 FSCTL_LOCK_VOLUMEFSCTL_DISMOUNT_VOLUME .

    Edit

    因为直接读取(或写入)没有缓冲,如果你想在更小的尺寸和扇区尺寸上操作,你必须自己处理缓冲 .

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

    #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 是针对小字节传输的随机搜索 . 如果有人需要按顺序传输大量数据,那么 SetMyDevicePosLoadNextMyDeviceSectormain 中的速度要快得多 .

    我更愿意用C编写这段代码 .

相关问题