如何有效地将结构向量写入文件?

Posted

技术标签:

【中文标题】如何有效地将结构向量写入文件?【英文标题】:How to efficiently write a vector of structs to file? 【发布时间】:2013-02-02 22:51:30 【问题描述】:

我的代码将大小大于 1000 万的向量写入文本文件。我使用 clock() 来计时 writefile 函数及其程序中最慢的部分。有没有比我下面的方法更好的写入文件的方法?

void writefile(vector<fields>& fieldsvec, ofstream& sigfile, ofstream& noisefile)
/* Writes clean and noise data to respective files
 *
 * fieldsvec: vector of clean data
 * noisevec: vector of noise data
 * sigfile: file to store clean data
 * noisefile: file to store noise data
 */

    for(unsigned int i=0; i<fieldsvec.size(); i++)
    
        if(fieldsvec[i].nflag==false)
        
            sigfile << fieldsvec[i].timestamp << ";" << fieldsvec[i].price << ";" << fieldsvec[i].units;
            sigfile << endl;
        
        else
        
            noisefile << fieldsvec[i].timestamp << ";" << fieldsvec[i].price << ";" << fieldsvec[i].units;
            noisefile << endl;
        
    

我的结构在哪里:

struct fields
// Stores a parsed line of a file

public:
    string timestamp;
    float price;
    float units;
    bool nflag; //flag if noise (TRUE=NOISE)
;

【问题讨论】:

你可以回退到 fread/fwrite 的旧 C i/o 函数,看看是否更快? 我打赌“fprintf()”会比ostream快很多——不幸的是,它需要一些重写,使用“FILE *”而不是“ost​​ream&”作为输入函数。 【参考方案1】:

我建议摆脱endl。这样每次都有效地刷新缓冲区,从而大大增加了系统调用的数量。

'\n'而不是endl应该是一个很好的改进。

顺便说一句,代码可以简化:

ofstream& files[2] =  sigfile, noisefile ;
for(unsigned int i=0; i<fieldsvec.size(); i++)
  files[fieldsvec[i].nflag] << fieldsvec[i].timestamp << ';' << fieldsvec[i].price << ";\n";

【讨论】:

@riotburn:我很想听听您使用未修改代码的计时结果,仅将std::endl 更改为'\n'。另请注意,ipc 推荐 character '\n',而不是 "\n"const char*。请让我们知道这种变化会带来什么样的不同! 所以在进行任何更改之前,writefile 需要 107.8 秒。使用“\n”现在需要 41.8 秒!使用 '\n' 需要 40.63 秒。有什么不同! @ipc 我尝试使用您将文件存储在数组中的聪明想法,但出现以下错误:scrub.cpp:174:22: error: declaration of ‘files’ as array of reference 我的虚拟机在打开一段时间后变得缓慢,所以我重新启动它,写入文件功能需要 35 秒。所以结果可能有点偏差,但它的对接加载速度更快。现在它是我最快的功能,所以我要努力加快读取和过滤功能。【参考方案2】:

您可以按照the first answer of this SO question 中的建议以二进制格式而不是文本格式编写文件以提高写入速度:

file.open(filename.c_str(), ios_base::binary);
...
// The following writes a vector into a file in binary format
vector<double> v;
const char* pointer = reinterpret_cast<const char*>(&v[0]);
size_t bytes = v.size() * sizeof(v[0]);
file.write(pointer, bytes);

从同一链接,OP 报告:

将 std::endl 替换为 \n 将代码速度提高了 1% 将所有要写入的内容串联在一个流中,最后将所有内容写入文件中,代码速度提高了 7% 将文本格式更改为二进制格式使他的代码速度提高了 90%。

【讨论】:

@riotburn:正如 Etienne 所建议的那样,您也非常想知道使用二进制 I/O 而非文本可以获得什么样的性能提升!请告诉我们! 这是一个很好的建议,但不幸的是我必须将其保留为文本格式。谢谢!【参考方案3】:

一个重要的速度杀手是您将数字转换为文本。

至于原始文件输出,ofstream 上的缓冲默认情况下应该非常有效。

您应该将数组作为 const 引用传递。这可能没什么大不了,但它确实允许某些编译器优化。

如果您认为流因为重复写入而搞砸了,您可以尝试使用sprintfsnprintf 创建一个字符串并写入一次。仅当您的时间戳是已知大小时才执行此操作。当然,这会产生额外的复制,因为必须将字符串放入输出缓冲区。实验。

否则,它会开始变脏。当您需要调整文件的性能时,您需要开始为您的应用程序定制缓冲区。这往往归结为不使用缓冲或缓存、对自己的缓冲区进行扇区对齐以及写入大块。

【讨论】:

以上是关于如何有效地将结构向量写入文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将字符数组写入文本文件

有效地将numpy数组写入二进制文件

如何使用 PHP 安全地将 JSON 数据写入文件

如何在python 3中有效地将原始字节写入numpy数组数据

如何有效地读取和写入太大而无法放入内存的文件?

将包含另一个向量的结构向量写入二进制文件