我需要将存档 (.zip) 解压到 USB 记忆棒中,但是在成功调用 CreateFile/WriteFile 之后,我从 WriteFile 得到各种错误,其中大部分是 INVALID_FD(GetLastError 给出错误代码 1006 ).请注意,当启动计算机(我正在使用虚拟化 Windows 11)并首次启动该程序时,它可以正常工作并完全解压缩存档。任何其他尝试都会失败。这是伪代码:
// *dst is my usb stick mounpoint, most of the time its "E:"
static int decompress_file(const char *zip, const char *dst)
{
struct zip_stat sb;
struct zip *za = zip_open(zip, ZIP_RDONLY, NULL);
for (long int i = 0; i < zip_get_num_entries(za, 0); i++) {
zip_stat_index(za, i, 0, &sb);
if (sb.valid & ZIP_STAT_NAME && sb.valid & ZIP_STAT_SIZE)
{
// Directory
if (sb.name[filename_length - 1] == '/') {
const std::string dir = std::string(dst) + sb.name;
#if defined(__linux__) || defined(__APPLE__)
if (mkdir(dir.c_str(), 0700) == -1 && errno != EEXIST)
#elif _WIN32
if (CreateDirectory(dir.c_str(), NULL) == -1 &&
GetLastError() != ERROR_ALREADY_EXISTS)
#endif
return _abort(__FILE__, __LINE__);
// File
} else {
const std::string file = std::string(dst) + sb.name;
struct zip_file *zf = zip_fopen_index(za, i, 0);
#if defined(__linux__) || defined(__APPLE__)
int fd = open(file.c_str(), O_RDWR | O_TRUNC | O_CREAT, 0644);
if (fd == -1)
return _abort(__FILE__, __LINE__);
#elif _WIN32
HANDLE fd = CreateFile(
file.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (fd == INVALID_HANDLE_VALUE)
return _abort(__FILE__, __LINE__);
#endif
size_t readLen, totalLen = 0;
char buffer[4096];
while (totalLen != sb.size) {
readLen = zip_fread(zf, buffer, 4096);
#if defined(__linux__) || defined(__APPLE__)
if (write(fd, buffer, readLen) == -1)
return _abort(__FILE__, __LINE__);
#elif _WIN32
if (!WriteFile(fd, buffer, readLen, NULL, NULL) &&
GetLastError() != ERROR_IO_PENDING)
return _abort(__FILE__, __LINE__);
#endif
totalLen += readLen;
}
#if defined(__linux__) || defined(__APPLE__)
close(fd);
#elif _WIN32
CloseHandle(fd);
#endif
zip_fclose(zf);
}
} else {
return _abort(__FILE__, __LINE__);
}
}
zip_close(za);
return 0;
}
我试图简化代码,请注意它不会按原样编译。我正在使用 libzip.
使用 open()/write() 的相同代码在 Linux/macOS 上运行良好。
这段代码在一个单独的线程上执行,主要是显示一个 GUI(wxwdiget)并等待这个任务完成。
我试着根据页面大小调整缓冲区大小,我猜对我们大多数人来说是 4096 字节?
在多次成功调用 CreateFile/WriteFile 之后,错误总是发生在程序执行的中端。
我尝试使用 procmon 和 processexplorer 监视我的程序,我正确地关闭了文件描述符,进程监视器上没有红旗,除了我向您描述的那个,这是错误触发时的事件属性部分在 procmon 上:
类:文件系统 操作:写文件 结果:文件无效 路径:E: oo ar oo..
偏移:73.400.320 长度:4096 I/O 标志:直写 优先级:普通
我还收到一个 0x80000016 错误,根据 msdn,它与常量 STATUS_VERIFY_REQUIRED 相关:“媒体已更改,验证操作正在进行中,所以没有 读或写可以被执行到设备,除了那些 用于验证操作。”
我看到直接写入外部驱动器(当使用 \.\ 语法作为物理驱动器打开时)必须扇区对齐,但这不是我的情况?我也尝试使用 _open/_write 进行切换,但遇到了完全相同的问题。你能帮帮我吗?
提前感谢您的帮助。