如何通过WinAPI获取盘符及物理驱动器的文件系统信息?
在Windows环境下,要搞清楚逻辑盘符(比如C:/、D:/)或者物理驱动器(比如//./PhysicalDrive0)的文件系统类型(比如是不是NTFS),最靠谱的方式就是直接调用Windows API来实现。下面分两种场景给你具体的实现思路和代码示例(用C++写的,毕竟直接调用系统接口最直观):
一、获取逻辑盘符的文件系统信息
对于C:/这类逻辑盘符,用GetVolumeInformation这个API就足够了,它能直接返回盘符的文件系统名称,不用绕弯子。
代码示例:
#include <windows.h> #include <iostream> #include <string> bool IsDriveNTFS(const std::wstring& drivePath) { WCHAR fileSystemName[MAX_PATH] = {0}; // 调用GetVolumeInformation,获取文件系统名称 if (!GetVolumeInformationW( drivePath.c_str(), nullptr, 0, // 不需要卷标信息 nullptr, // 不需要序列号 nullptr, // 不需要最大组件长度 nullptr, // 不需要文件系统标志 fileSystemName, MAX_PATH )) { std::cerr << "Failed to get volume information. Error code: " << GetLastError() << std::endl; return false; } // 不区分大小写比较文件系统名称 return _wcsicmp(fileSystemName, L"NTFS") == 0; } int main() { std::wstring drive = L"C:\\"; if (IsDriveNTFS(drive)) { std::wcout << drive << " is NTFS." << std::endl; } else { std::wcout << drive << " is not NTFS." << std::endl; } return 0; }
关键点说明:
- 传入的盘符路径必须以
\\结尾(比如L"C:\\"),不然API会调用失败。 _wcsicmp是不区分大小写的字符串比较,避免因为大小写问题误判。- 调用失败时用
GetLastError()能拿到具体错误码,方便排查(比如盘符不存在、权限不足等)。
二、获取物理驱动器的文件系统信息
物理驱动器本身没有单一的文件系统——它是由多个分区组成的,每个分区有自己的文件系统。所以我们得先枚举物理驱动器上的所有分区,再逐个查询每个分区的文件系统类型。
这里需要用到几个IOCTL控制码:IOCTL_DISK_GET_DRIVE_GEOMETRY_EX(获取驱动器几何信息和分区表),然后针对每个分区打开对应的设备(比如//./PhysicalDrive0Partition1),再用GetVolumeInformation或者IOCTL_VOLUME_GET_VOLUME_INFORMATION查询文件系统。
代码示例:
#include <windows.h> #include <iostream> #include <string> #include <vector> // 简化的分区信息结构体 struct PartitionInfo { LARGE_INTEGER offset; LARGE_INTEGER length; int number; }; // 枚举物理驱动器上的所有分区 std::vector<PartitionInfo> EnumeratePartitions(const std::wstring& physicalDrivePath) { std::vector<PartitionInfo> partitions; HANDLE hDrive = CreateFileW( physicalDrivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr ); if (hDrive == INVALID_HANDLE_VALUE) { std::cerr << "Failed to open physical drive. Error code: " << GetLastError() << std::endl; return partitions; } // 获取驱动器几何信息和分区表 DISK_GEOMETRY_EX geometryEx = {0}; DWORD bytesReturned = 0; if (!DeviceIoControl( hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, nullptr, 0, &geometryEx, sizeof(geometryEx), &bytesReturned, nullptr )) { std::cerr << "Failed to get drive geometry. Error code: " << GetLastError() << std::endl; CloseHandle(hDrive); return partitions; } // 遍历分区表(兼容MBR/GPT,API会自动返回对应类型) PARTITION_INFORMATION_EX* pPartitions = reinterpret_cast<PARTITION_INFORMATION_EX*>(geometryEx.Buffer); DWORD partitionCount = geometryEx.PartitionCount; for (DWORD i = 0; i < partitionCount; ++i) { PartitionInfo info; info.offset = pPartitions[i].StartingOffset; info.length = pPartitions[i].PartitionLength; info.number = i + 1; // 分区编号从1开始 partitions.push_back(info); } CloseHandle(hDrive); return partitions; } // 查询指定分区是否为NTFS bool IsPartitionNTFS(const std::wstring& physicalDrivePath, int partitionNumber) { // 构造分区设备路径,比如//./PhysicalDrive0Partition1 std::wstring partitionPath = physicalDrivePath + L"Partition" + std::to_wstring(partitionNumber); HANDLE hPartition = CreateFileW( partitionPath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr ); if (hPartition == INVALID_HANDLE_VALUE) { std::cerr << "Failed to open partition " << partitionNumber << ". Error code: " << GetLastError() << std::endl; return false; } WCHAR fileSystemName[MAX_PATH] = {0}; bool isNTFS = false; // 先尝试用GetVolumeInformation查询 if (GetVolumeInformationW( partitionPath.c_str(), nullptr, 0, nullptr, nullptr, nullptr, fileSystemName, MAX_PATH )) { isNTFS = (_wcsicmp(fileSystemName, L"NTFS") == 0); } else { // 如果失败, fallback 到IOCTL直接查询分区设备 VOLUME_INFORMATION_BUFFER volumeInfo = {0}; DWORD bytesReturned = 0; if (DeviceIoControl( hPartition, IOCTL_VOLUME_GET_VOLUME_INFORMATION, nullptr, 0, &volumeInfo, sizeof(volumeInfo), &bytesReturned, nullptr )) { isNTFS = (_wcsicmp(volumeInfo.FileSystemName, L"NTFS") == 0); } else { std::cerr << "Failed to get partition volume info. Error code: " << GetLastError() << std::endl; } } CloseHandle(hPartition); return isNTFS; } int main() { std::wstring physicalDrive = L"\\\\.\\PhysicalDrive0"; auto partitions = EnumeratePartitions(physicalDrive); if (partitions.empty()) { std::wcout << "No partitions found on " << physicalDrive << std::endl; return 1; } for (const auto& part : partitions) { bool isNTFS = IsPartitionNTFS(physicalDrive, part.number); std::wcout << physicalDrive << L"Partition" << part.number << " is " << (isNTFS ? L"NTFS" : L"not NTFS") << std::endl; } return 0; }
关键点说明:
- 打开物理驱动器需要管理员权限,不然会提示权限不足(错误码5)。
- 有些分区没有挂载盘符,
GetVolumeInformation会失败,这时候用IOCTL_VOLUME_GET_VOLUME_INFORMATION直接从分区设备获取信息更可靠。 - 分区设备的命名规则是
//./PhysicalDriveXPartitionY,X是驱动器编号,Y是分区编号(从1开始)。
如果用C#、Python这类语言,思路也一样——通过P/Invoke(C#)或者ctypes(Python)调用对应的Windows API即可,核心逻辑没有区别。
内容的提问来源于stack exchange,提问作者Tomasz Nowakowski
相关产品推荐
相关产品推荐

