windows api读取ads必须用createfile配合宽字符路径“文件名:流名”,不可用fopen或标准库;失败时检查getlasterror,常见错误包括error_path_not_found、error_file_not_found和error_invalid_parameter。

Windows API 读取 ADS 的核心是 CreateFile
ADS 不是普通文件,不能用 fopen 或 std::ifstream 直接打开。必须用 Windows 原生 API,关键函数是 CreateFile,且路径需显式拼上流名,格式为 "filename:streamname"。
常见错误是漏掉冒号或把流名当子目录(比如写成 "filenamestreamname"),这会返回 INVALID_HANDLE_VALUE,GetLastError() 通常是 ERROR_PATH_NOT_FOUND 或 ERROR_INVALID_NAME。
- 流名不区分大小写,但建议保持小写以避免混淆
- 主数据流(即默认内容)对应空流名,
"file.txt:"是合法路径,但读出来就是主文件内容 - 如果目标文件在 NTFS 卷外(如 FAT32、网络映射盘、WSL2 的 /mnt/c),
CreateFile会失败,GetLastError()返回ERROR_INVALID_PARAMETER
正确构造 ADS 路径并打开句柄
路径字符串必须是宽字符(LPCWSTR),且不能包含非法字符(如 : " | ? * —— 流名本身受限更严,连 / 和 . 都可能被拒绝)。推荐用 std::wstring 拼接:
std::wstring path = L"C:\test.txt:secret";
HANDLE h = CreateFile(
path.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
注意:dwCreationDisposition 必须是 OPEN_EXISTING;用 CREATE_ALWAYS 会清空主文件,不是创建流。
- 若流不存在,
CreateFile失败,GetLastError()返回ERROR_FILE_NOT_FOUND - 权限不足时(如只读文件 + 尝试写入流),返回
ERROR_ACCESS_DENIED - 路径长度超
MAX_PATH(260)?加前缀L"\\?\",例如L"\\?\C:\very\long\path.txt:meta"
读取内容后记得 CloseHandle
拿到有效 HANDLE 后,用 ReadFile 读取,和普通文件无异。但 ADS 没有标准长度属性——GetFileSize 对流返回 INVALID_FILE_SIZE,必须先调用 GetCompressedFileSize 或更稳妥地用 GetFileInformationByHandle 获取 dwFileSizeLow(对 ADS 是真实字节数)。
- 流可以为空(0 字节),此时
ReadFile成功但*lpNumberOfBytesRead == 0 - 不要假设流一定存在:每次操作前都应检查
h != INVALID_HANDLE_VALUE - 忘记
CloseHandle(h)会导致句柄泄漏,多次重复操作后可能触发系统限制
C++ 标准库完全不支持 ADS
std::filesystem::exists、std::filesystem::file_size 等函数对 "file:stream" 路径一律返回 false 或抛异常,因为它们走的是 POSIX 兼容层,根本解析不了冒号语法。所有 ADS 操作必须绕过标准库,直连 Win32 API。
有人试图用 std::fstream 配合 _wfopen,但后者内部仍调用 CreateFile,且不接受冒号路径 —— 它会把 : 当作驱动器分隔符处理,直接失败。
真正麻烦的点不在读取本身,而在于:没有跨平台抽象层,没有 RAII 封装,每个 ADS 操作都要手动管理句柄、检查错误、转换编码、处理路径边界。哪怕只是判断某个流是否存在,也得走一遍 CreateFile → CloseHandle 流程。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











