读取巨大的二进制文件 (~1.5 GB) 并将结果写入文本文件 C++

Reading huge binary file (~1.5 GB) and writing the results to a text file C++

提问人:Guled 提问时间:10/31/2022 更新时间:10/31/2022 访问量:101

问:

我正在尝试逐块读取一个巨大的二进制文件,解码每个块并将其输出到文本文件中,以便于故障排除。到目前为止,我已经编写了一个代码来做到这一点,但它非常慢(需要几个小时才能解码整个文件)。

这是我的代码:

template<class T> std::vector<T> readBytes(std::ifstream& input, int numOfBytes) {
    std::vector<T> output;
    output.reserve(numOfBytes);

    T* buf = new T[numOfBytes];
    input.read((char*)buf, sizeof(T) * numOfBytes);

    for (int i = 0; i < numOfBytes; ++i) {
        output.push_back(buf[i]);
    }
    
    delete[] buf;
    return output;
}

std::ifstream file("lidar_Mission.dat", std::ios::binary | std::ios::ate);
std::streampos total_bytes(file.tellg());
file.seekg(12, std::ios::beg); //skip the header

while (file) {
    if (file.good()) {
        //Read the required chunk and store it in a vector
        std::vector<std::int8_t> time(readBytes<std::int8_t>(file, 8));
        std::vector<std::int8_t> lidarx(readBytes<std::int8_t>(file, 4));
        std::vector<std::int8_t> lidary(readBytes<std::int8_t>(file, 4));
        std::vector<std::int8_t> lidarz(readBytes<std::int8_t>(file, 4));
        std::vector<std::int8_t> intensity(readBytes<std::int8_t>(file, 2));
        std::vector<char> classification(readBytes<char>(file, 1));
        std::vector<char> Return_scan(readBytes<char>(file, 1));

        uint8_t timeArr[8] = { time[0], time[1],time[2],time[3],time[4],time[5],time[6],time[7] };
        uint8_t lidarxArr[4] = { lidarx[0], lidarx[1],lidarx[2],lidarx[3] };
        uint8_t lidaryArr[4] = { lidary[0], lidary[1],lidary[2],lidary[3] };
        uint8_t lidarzArr[4] = { lidarz[0], lidarz[1],lidarz[2],lidarz[3] };
        uint8_t intenArr[2] = { intensity[0], intensity[1] };
        uint8_t clssArr[1] = { classification[0]};
        uint8_t Retn_scnArr[1] = { Return_scan[0]};
                
        //Type punning
        double timestamp = *((double*)&timeArr);
        float x = *((float*)lidarxArr);
        float y = *((float*)lidaryArr);
        float z = *((float*)lidarzArr);
        uint16_t inten = *((uint16_t*)intenArr);
        uint8_t clss = *((uint8_t*)clssArr);
        uint8_t Retn_scn = *((uint8_t*)Retn_scnArr);
        
        //Write to a text file
        std::ofstream fout;

        fout.open("test2", std::ios::out | std::ios::app);

        fout << std::fixed << std::setprecision(9) << std::left << std::setw(19) << timestamp
            << std::setprecision(10) << std::setw(15) << x
            << std::setprecision(10) << std::setw(15) << y
            << std::setw(16) << z
            << std::setw(10) << inten
            << std::endl;
        fout.close();
    }else{
        throw std::exception();
    }
}


关于如何让它运行得更快的任何想法?谢谢


C++ 文件-IO IOstream

评论

1赞 Mark Ransom 10/31/2022
read()是一项高开销操作。尝试读取较大的块文件并在这些块中工作。
0赞 Kevin 10/31/2022
你为什么要读入一个数组,循环它,把它放到一个向量中,然后再读一个数组?只需向量并直接读取其中。newdeleteresize
0赞 Mark Tolonen 10/31/2022
构建所有这些载体是一种浪费。看起来你应该一口气直接阅读它。如果输入文件只是该结构的倍数数组,则可以一次读取一大块中的大量数据。structdouble, float, float, float, uint16_t, uint8_t, uint8_t
0赞 Guled 10/31/2022
感谢先生们的建议。
0赞 Guled 10/31/2022
@Kevin,对不起,你到底是什么意思?我必须先读入缓冲区,对吧?如何直接读取向量?

答:

0赞 psimpson 10/31/2022 #1

尽可能多地在循环外执行操作,尤其是 I/O。在进入循环之前打开一次,退出循环后关闭一次。如果出现任何致命错误,也要关闭文件,并指示操作失败的原因。

您还可以测试将其他声明移到循环之外,引用其中的预定义变量。如果您不确定编译器是否可以优化类似的东西,那么这是一个易于运行的测试。

评论

0赞 Guled 10/31/2022
谢谢@psimpson。一定会尝试的。