`WriteFile` 写入 U 盘时出错

问题描述 投票:0回答:0

我需要将存档 (.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 之后,错误总是发生在程序执行的中端。

我尝试使用 procmonprocessexplorer 监视我的程序,我正确地关闭了文件描述符,进程监视器上没有红旗,除了我向您描述的那个,这是错误触发时的事件属性部分在 procmon 上:

类:文件系统 操作:写文件 结果:文件无效 路径:E: oo ar oo..

偏移:73.400.320 长度:4096 I/O 标志:直写 优先级:普通

我还收到一个 0x80000016 错误,根据 msdn,它与常量 STATUS_VERIFY_REQUIRED 相关:“媒体已更改,验证操作正在进行中,所以没有 读或写可以被执行到设备,除了那些 用于验证操作。”

来源: https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-FSCC/%5BMS-FSCC%5D-130808.pdf

我看到直接写入外部驱动器(当使用 \.\ 语法作为物理驱动器打开时)必须扇区对齐,但这不是我的情况?我也尝试使用 _open/_write 进行切换,但遇到了完全相同的问题。你能帮帮我吗?

提前感谢您的帮助。

c++ windows io usb-drive
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.