httplib库的使用(文件分块传输chunked data)(二)

1. 说明

http如果要传输的文件很大,则需要使用到分块传输。使用分块传输的方式,客户端和服务器都不用在内存里保存文件的全部,每次只收发一小部分即可。

在响应报文里用头字段 “Transfer-Encoding: chunked” 表示报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)分批发送。

httplib库提供两种方式将大文件分块发送。分别是set_chunked_content_providerset_content_provider

2. 两种方式的区别

如果使用"set_chunked_content_provider",需手动在所有数据写入到sink后调用sink.done(),而set_content_provider则不需要,后者只需将文件大小作为一个参数传递即可。

3. set_chunked_content_provider方式

svr.Get("/test", [=](const httplib::Request& req, httplib::Response& resp)
{
    // file path 文件路径
    const char* file_path = "D:/Project/test.zip";
    
    // 404 not found, can't open file
    if (!std::ifstream(file_path, std::ifstream::binary | std::ifstream::in).good()) {
        resp.status = 404;
        resp.set_content("404 not found", "text/plain; charset=UTF-8");
        return;
    }

    resp.set_chunked_content_provider("application/octet-stream", [file_path](size_t offset, httplib::DataSink& sink) {
        // open file
        std::ifstream file_reader(file_path, std::ifstream::binary | std::ifstream::in);

        // can't open file, cancel process
        if (!file_reader.good())
            return false;

        // get file size
        file_reader.seekg(0, file_reader.end);
        size_t file_size = file_reader.tellg();
        file_reader.seekg(0, file_reader.beg);

        // check offset and file size, cancel process if offset >= file_size
        if (offset >= file_size)
            return false;
        
        // larger chunk size get faster download speed, more memory usage, more bandwidth usage, more disk I/O usage
        const size_t chunk_size = 32 * 1024;

        // prepare read size of chunk
        size_t read_size = 0;
        bool last_chunk = false;
        if (file_size - offset > chunk_size) {
            read_size = chunk_size;
            last_chunk = false;
        } else {
            read_size = file_size - offset;
            last_chunk = true;
        }

        // allocate temp buffer, and read file chunk into buffer
        std::vector<char> buffer;
        buffer.reserve(chunk_size);
        file_reader.seekg(offset, file_reader.beg);
        file_reader.read(&buffer[0], read_size);
        file_reader.close();

        // write buffer to sink
        sink.write(&buffer[0], read_size);

        // done after last chunk had write to sink
        if (last_chunk)
            sink.done();

        return true;
    });
});

4. set_content_provider方式

svr.Get("/test1", [=](const httplib::Request& req, httplib::Response& resp) {
    // open file
    const char* file_path = "D:/Project/hf_server/output/win64/bin/Debug/www/test.zip";
    std::ifstream file_reader(file_path, std::ifstream::binary | std::ifstream::in);

    // 404 not found
    if (!file_reader.good()) {
        resp.status = 404;
        resp.set_content("404 not found", "text/plain; charset=UTF-8");
        return;
    }

    // get file size
    file_reader.seekg(0, file_reader.end);
    size_t file_size = file_reader.tellg();
    file_reader.seekg(0, file_reader.beg);

    resp.set_content_provider(file_size, 
        "application/octet-stream",
        [file_path](size_t offset, size_t length, httplib::DataSink& sink) {
        // open file
        std::ifstream file_reader(file_path, std::ifstream::binary | std::ifstream::in);

        // can't open file, cancel process
        if (!file_reader.good())
            return false;

        // get file size
        file_reader.seekg(0, file_reader.end);
        size_t file_size = file_reader.tellg();
        file_reader.seekg(0, file_reader.beg);

        // check offset and file size, cancel process if offset >= file_size
        if (offset >= file_size)
            return false;

        // larger chunk size get faster download speed, more memory usage, more bandwidth usage, more disk I/O usage
        const size_t chunk_size = 32 * 1024;

        // prepare read size of chunk
        size_t read_size = 0;
        if (file_size - offset > chunk_size){
            read_size = chunk_size;
        } else {
            read_size = file_size - offset;
        }

        // allocate temp buffer, and read file chunk into buffer
        std::vector<char> buffer;
        buffer.reserve(chunk_size);
        file_reader.seekg(offset, file_reader.beg);
        file_reader.read(&buffer[0], read_size);
        file_reader.close();

        // write buffer to sink
        sink.write(&buffer[0], read_size);

        return true;
    });
});
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值