You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在libzip中使用std::istream替代文件?

Great question—libzip doesn’t make this super obvious at first glance, but you can absolutely create a struct zip* directly from a std::istream without writing to the filesystem by leveraging zip sources, the library’s mechanism for working with custom data inputs.

Solution: Use Custom Zip Sources with std::istream

Libzip allows you to define custom data sources via zip_source objects. You can create a source that reads directly from your std::istream using callback functions, then open that source to get your struct zip*.

Step-by-Step Implementation

Here's a complete, corrected example that fixes the issues in your original code and implements the stream-based zip source:

#include <libzip/zip.h>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <sstream>

// C-style callback to read data from the std::istream
static zip_int64_t stream_read_callback(void* userdata, void* buffer, zip_uint64_t len) {
    auto* stream = static_cast<std::istream*>(userdata);
    stream->read(static_cast<char*>(buffer), len);
    return stream->gcount(); // Return actual bytes read
}

// Optional callback for seeking (required for random-access zip operations)
static zip_int64_t stream_seek_callback(void* userdata, zip_int64_t offset, int whence) {
    auto* stream = static_cast<std::istream*>(userdata);
    std::ios_base::seekdir dir;
    switch (whence) {
        case SEEK_SET: dir = std::ios_base::beg; break;
        case SEEK_CUR: dir = std::ios_base::cur; break;
        case SEEK_END: dir = std::ios_base::end; break;
        default: return -1; // Invalid seek direction
    }
    stream->seekg(offset, dir);
    return stream->tellg(); // Return new position
}

// Cleanup callback (no-op here since we don't own the stream)
static void stream_cleanup_callback(void* userdata) {
    // If you allocated the stream dynamically, delete it here
}

int main() {
    try {
        // Example: Use a std::istringstream (works with any std::istream: cin, network streams, etc.)
        std::istringstream zip_stream(R"(/* Your raw zip data here */)");

        // Create the zip source using our callbacks
        zip_error_t err;
        zip_source_t* source = zip_source_function_create(
            stream_read_callback,
            &zip_stream,
            stream_seek_callback,
            stream_cleanup_callback,
            &err
        );

        if (!source) {
            char err_buf[256];
            zip_error_to_str(err_buf, sizeof(err_buf), &err, 0);
            throw std::runtime_error(std::string("Failed to create zip source: ") + err_buf);
        }

        // Open the zip archive directly from the source
        struct zip* zip_file = zip_open_from_source(source, 0, &err);
        if (!zip_file) {
            zip_source_free(source); // Clean up source if opening fails
            char err_buf[256];
            zip_error_to_str(err_buf, sizeof(err_buf), &err, 0);
            throw std::runtime_error(std::string("Failed to open zip from source: ") + err_buf);
        }

        // Extract the first file in the zip (same as your original logic, fixed)
        struct zip_file* file_in_zip = zip_fopen_index(zip_file, 0, 0);
        if (!file_in_zip) {
            zip_close(zip_file);
            throw std::runtime_error("Failed to open file inside zip archive");
        }

        char buff[1024];
        std::ofstream extracted("extracted_data");
        zip_int64_t readed;
        while ((readed = zip_fread(file_in_zip, buff, 1024)) > 0) {
            extracted.write(buff, readed);
        }

        // Cleanup resources (zip_close frees the source automatically)
        zip_fclose(file_in_zip);
        zip_close(zip_file);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

Key Details to Note

  • Callback Roles:
    • stream_read_callback: Pulls data from your std::istream into libzip's buffer.
    • stream_seek_callback: Enables random access in the zip archive (skip this if your stream doesn't support seeking, but some zip operations may fail).
    • stream_cleanup_callback: Handles cleanup of your user data (leave empty if you manage the stream's lifecycle externally).
  • Ownership: After a successful zip_open_from_source, calling zip_close(zip_file) automatically frees the associated zip_source_t—no need to call zip_source_free separately.
  • Error Handling: Always validate return values and use zip_error_to_str to get human-readable error messages.

Edge Case: Non-Seekable Streams

If your std::istream doesn't support seeking (e.g., a network stream), pass nullptr instead of stream_seek_callback. Keep in mind that some zip operations (like accessing non-consecutive files) may not work, as libzip relies on seeking for random access.

内容的提问来源于stack exchange,提问作者Max Krantov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:47:57