c++怎样把二进制文件按字节读到vector<unsigned char>中?

作者:黄兢成
链接:https://www.zhihu.com/question/52359180/answer/130202972
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

我读文件都是使用 FILE,方法 1 是我在实际工程中使用的,本来是模板实现,可以读取到 std::string、std::vector<char>、std::vector<unsigned char>。想速度快,尽可能一次读取。Relase 编译,在我电脑上,读取 1.67 G的电影文件,耗时如下。

readFromFile1 耗时 1.49 s

readFromFile2 耗时 6.42 s

readFromFile3 耗时 4.82 s

readFromFile4 耗时 4.37 s

当然每次程序运行,数值有所偏差。但耗时顺序不变。大家可以运行看看(需要换掉文件路径)。

附上电脑配置和 Disk Speed Test 测试的磁盘速度。

#include <fstream>
#include <vector>
#include <cassert>
#include <boost/progress.hpp>

static size_t getFileSize(FILE* file) {
    fseek(file, 0, SEEK_END);
    size_t read_len = ftell(file);
    fseek(file, 0, SEEK_SET);
    return read_len;
}

static size_t getFileSize(const char* filePath) {
    FILE* file = fopen(filePath, "rb");
    if (file == nullptr) {
        return 0;
    }
    size_t size = getFileSize(file);
    fclose(file);
    return size;
}

// 方法 1
std::vector<unsigned char> readFromFile1(const char* filePath) {
    FILE* file = fopen(filePath, "rb");
    std::vector<unsigned char> result;
    if (file == nullptr) {
        return result;
    }

    // 获取文件大小,尽量一次读完
    size_t fileSize = getFileSize(file);
    if (fileSize != 0) {
        result.resize(fileSize);
        size_t n = fread(&result[0], 1, fileSize, file);
        assert(n <= fileSize);
        if (n != fileSize) {
            result.resize(n);
        }
    }

    // 在读取过程当中,有可能文件大小有变化,再尝试读取
    const size_t read_len = 1024;
    char buf[read_len];
    for (;;) {
        size_t n = fread(buf, 1, read_len, file);
        result.insert(result.end(), buf, buf + n);
        if (n < read_len) {
            break;
        }
    }
    fclose(file);
    return result;
}

// 方法 2
std::vector<unsigned char> readFromFile2(const char* filePath) {
    std::ifstream inputFile(filePath, std::ios::binary);
    std::vector<unsigned char> fileData((std::istreambuf_iterator<char>(inputFile)),
                                        std::istreambuf_iterator<char>());
    return fileData;
}

// 方法 3,在方法 2 基础上调用 reserve
std::vector<unsigned char> readFromFile3(const char* filePath) {
    std::vector<unsigned char> fileData;
    fileData.reserve(getFileSize(filePath));
    
    std::ifstream inputFile(filePath, std::ios::binary);
    fileData.insert(fileData.end(),
                    std::istreambuf_iterator<char>(inputFile),
                    std::istreambuf_iterator<char>());
    
    return fileData;
}

// 方法 4,思路同方法 1, 只是换了 ifstream 实现,没有考意外情况,只测量速度
std::vector<unsigned char> readFromFile4(const char* filePath) {
    std::vector<unsigned char> fileData;
    std::ifstream inputFile(filePath, std::ios::binary);
    inputFile.seekg(0, std::ios::end);
    fileData.resize(inputFile.tellg());
    inputFile.seekg(0);
    inputFile.read(reinterpret_cast<char*>(fileData.data()), fileData.size());
    return fileData;
}


int main(int argc, const char* argv[]) {
    const char* filePath = "/电影/[阳光电影www.ygdy8.com].使徒行者.BD.720p.国粤双语中字.mkv";
    {
        boost::progress_timer t;
        readFromFile1(filePath);
    }
    
    {
        boost::progress_timer t;
        readFromFile2(filePath);
    }
    
    {
        boost::progress_timer t;
        readFromFile3(filePath);
    }

    {
        boost::progress_timer t;
        readFromFile4(filePath);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值