如何在c

时间:2017-10-05 18:00:18

标签: c windows storage device

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

Read and write hard disk sector directly and efficiently

Read specific sector on hard drive using C language on windows

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

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

  1. 声明变量
  2. 初始化变量
  3. SetFilePointer()
  4. 的ReadFile()
  5. 将读取的字节输出到文件
  6. 使用ReadFile()获取更多字节
  7. 再次将读取的字节输出到同一文件
  8. 重复6和7(实际上只重复4和5)
  9. 这似乎不起作用。我想读取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:

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

1 个答案:

答案 0 :(得分:3)

87表示INVALID PARAMETER。

你的读取必须是扇区对齐的,所以你不能寻求偏移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是针对小字节传输的随机搜索。如果有人需要按顺序传输大量数据,那么SetMyDevicePos LoadNextMyDeviceSector#3 main中的InvalidOperationException要快得多。

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