Winapi 从物理硬盘读取数据

Winapi 从物理硬盘读取数据,winapi,visual-c++,file-io,hard-drive,Winapi,Visual C++,File Io,Hard Drive,我正在尝试开发一个程序,可以找到2个连接的未格式化物理驱动器并读取字节。该程序目前在管理员模式下运行,因为我猜这是该程序查看未格式化硬盘驱动器的唯一方式。我使用的是visual studio 2015,它在windows 7计算机上运行 问题是它只能读取512的倍数(512是扇区大小)。目前,未格式化硬盘驱动器位于磁盘2和3插槽中(它们都是SSD)。它首先读取512字节(工作时没有问题),如果是格式化硬盘,则不再进行读取。如果是未格式化的硬盘,它会继续读取更多字节。如果它是硬盘驱动器A,那么它将

我正在尝试开发一个程序,可以找到2个连接的未格式化物理驱动器并读取字节。该程序目前在管理员模式下运行,因为我猜这是该程序查看未格式化硬盘驱动器的唯一方式。我使用的是visual studio 2015,它在windows 7计算机上运行

问题是它只能读取512的倍数(512是扇区大小)。目前,未格式化硬盘驱动器位于磁盘2和3插槽中(它们都是SSD)。它首先读取512字节(工作时没有问题),如果是格式化硬盘,则不再进行读取。如果是未格式化的硬盘,它会继续读取更多字节。如果它是硬盘驱动器A,那么它将读取接下来的1024个字节,并且可以正常工作(read_amount=1024)。如果它是硬盘驱动器B,那么它将读取接下来的1025字节,但它不工作(read_amount=0)。我不知道为什么它不能读取512/扇区大小的倍数。我的理解是,当您使用dwFlagsAndAttributes=FILE\u ATTRIBUTE\u NORMAL调用“CreateFile()”函数时,我应该能够读取不是扇区大小倍数的大小(如果您使用FILE\u FLAG\u NO\u缓冲,那么您只能读取512的倍数,而我没有使用该标志)。请参阅下面的代码

//Hard_Drive_Read.cpp:定义控制台应用程序的入口点

//此程序假定您的计算机上正好连接了两个未格式化的硬盘驱动器

#include <Windows.h>
#include <io.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <iomanip>


using namespace std;




int main(int argc, char *argv[])
{
if (argc != 3)
{
    cout << "Need to enter 2 arguments" << endl;
    exit(0);
}

int frames_to_process = atoi(argv[2]);

if (frames_to_process < 1)
{
    cout << "invalid argument 2" << endl;
    exit(0);
}



//HANDLE hDisk_A;
//HANDLE hDisk_B;



LPCTSTR dsksrc = L"\\\\.\\PhysicalDrive";
wchar_t dsk[512] = L"";


bool channel_A_found = false;
bool channel_B_found = false;
char frame_header_A[1024];
char frame_header_B[1025];



HANDLE hDisk;
char buff_read[512];
DWORD read_amount = 0;

for (int i = 0; i < 4; i++)
{


    swprintf(dsk, 511, L"%s%d", dsksrc, i);

    hDisk = CreateFile(dsk, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hDisk == INVALID_HANDLE_VALUE)
    {
        printf("%s%d%s", "couldn't open the drive ", i, "\n");
        CloseHandle(hDisk);
    }
    else
    {
        printf("%s%d%s", "successfully open the drive ", i, "\n");

        BOOL read_success_1 = ReadFile(hDisk, buff_read, 512, &read_amount, NULL);
        cout << "read amount 1 - " << read_amount << endl;
        if ((read_success_1 == TRUE) && (read_amount == 512))
        {


            if ((buff_read[510] == (char)0x55) && (buff_read[511] == (char)0xAA))  //  test for a formatted drive; is there other identifiers?
            {
                cout << i << " is a formatted drive" << endl;
            }

            else
            {
                cout << "Not a formatted drive, trying to find sync " << endl;


                ofstream writeBinary_Test;

                if (i == 2)
                {
                    writeBinary_Test.open("file_A_test.bin", ofstream::out | ofstream::binary);
                    ReadFile(hDisk, frame_header_A, 1024, &read_amount, NULL);
                    cout << "read amount " << read_amount << endl;
                    writeBinary_Test.write(frame_header_A, 1024);
                    writeBinary_Test.close();
                }

                else if(i == 3)
                {
                    writeBinary_Test.open("file_B_test.bin", ofstream::out | ofstream::binary);
                    ReadFile(hDisk, frame_header_B, 1025, &read_amount, NULL);
                    cout << "read amount " << read_amount << endl;
                    writeBinary_Test.write(frame_header_B, 1025);
                    writeBinary_Test.close();
                }



                LARGE_INTEGER distanceToMove;      
                SetFilePointerEx(hDisk, distanceToMove, NULL, FILE_BEGIN);



            }
        }

        else
        {

        }

    }

    if (channel_A_found && channel_B_found)
    {
        cout << "both drives found" << endl;
        break;
    }
}


if ((channel_A_found == false) || (channel_B_found == false))
{
    cout << "Couldn't Find Hard Drive A or Drive B or Both" << endl;
    cout << "Exiting the program" << endl;
    exit(0);
}


CloseHandle(hDisk);



return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(int argc,char*argv[])
{
如果(argc!=3)
{
库特
我必须能够读取不是512倍数的大小

这是不可能的。对于直接访问磁盘,您只能读取和写入扇区大小的倍数。此外,您必须对齐读取和写入操作。也就是说,文件指针必须是扇区大小的倍数

如果您希望提供一个允许任意查找、读取和写入的接口,则需要在对齐的原始磁盘访问上实现自己的缓冲。

说明:

卷句柄可以由特定文件系统自行决定以非缓存方式打开,即使CreateFile中未指定“非缓存”选项。您应该假设所有Microsoft文件系统都以非缓存方式打开卷句柄。对文件的非缓存I/O的限制也适用于卷

虽然没有明确说明,但这适用于驱动器和卷


实际上,这不是一个问题。编写一个助手函数可以直接从任意偏移量返回任意数量的数据,同时只执行对齐读取。

当使用文件标志无缓冲打开的文件时,应用程序必须满足某些要求。以下具体说明适用:•文件访问大小,包括重叠结构中的可选文件偏移量(如果指定),必须是卷扇区大小整数倍的字节数。例如,如果扇区大小为512字节,应用程序可以请求512、1024、1536或2048字节的读写,但不能请求335、981或7171字节的读写。如果se FILE_ATTRIBUTE_NORMAL?缓冲是一种更高级别的功能,在处理卷时可以使用。直接访问磁盘时,没有缓冲,必须使用对齐访问。我最初尝试使用_open_osfhandle()函数和_fdopen()将句柄转换为文件指针。它基本上是工作的,但后来我意识到fseek()和fread()并不总是工作。例如,当我做的fseek不是512的倍数(正数)时,fread无法在扇区内开始读取(它总是从扇区的开头开始)。但是,如果它有一个负偏移量,它工作得很好。然后我决定使用这种方法。你有没有从无格式硬盘读取不是扇区大小倍数的字节的想法?我感谢你的评论。我不知道如何才能更清楚地回答我的问题。很抱歉,我是个坏消息的传递者。但你只是想必须接受对齐访问的需要。如果您需要提供一个未对齐的接口,请添加您自己的缓冲层。我在回答中已经说过所有这些。我现在已经重复了。我没有更多要添加的内容。谢谢,我想我必须为SetFilePointerEx()编写一个帮助器函数还有。我希望一切都能像fseek()和fread()那样运行。有几个问题,1)我不太理解卷和磁盘之间的区别。我假设卷是磁盘的一种逻辑形式,磁盘访问速度比卷访问速度快吗?2)我也读过一些人,所以使用fread比ReadFile()性能更好。只要您使用ReadFile()启用缓存它还能比fread慢吗?
fread
是一个C运行时库函数,它最终调用
ReadFile
来完成实际的工作。因为它在用户模式下缓冲数据,如果你进行大量的小读取,它的性能可能比
ReadFile
更好。卷之间的主要区别,例如
\.\C:
而一个驱动器
\\。\PhysicalDrive0
是指一个驱动器代表整个硬盘驱动器,一个卷代表单个分区。您也在与不同的驱动程序级别交谈,因此可能在语义上存在一些差异,我想不起任何细节。当然,您可以实现自己的
fread
fseek
等同物。如果您使用Visual Studio,您甚至可以查看C运行时库源代码以了解Microsoft是如何做到这一点的。
ReadFile
检查
FO_NO_INTERMEDIATE_BUFFERING
标记,如果它将check buffer size和offset设置为multiple
DeviceObject->SectorSize
。何时是
fou NO_in命名为中间缓冲
标志集?I/O子系统在使用文件
中间缓冲时进行设置