C++ c++;读取大量文件的一小部分
我有一个相对简单的问题要问,关于许多编程语言,关于哪种方法提供最快的文件读取速度,一直在进行讨论。主要讨论的是C++ c++;读取大量文件的一小部分,c++,c,linux,performance,file,C++,C,Linux,Performance,File,我有一个相对简单的问题要问,关于许多编程语言,关于哪种方法提供最快的文件读取速度,一直在进行讨论。主要讨论的是read()或mmap()。作为一个也参与了这些辩论的人,我没有找到我当前问题的答案,因为大多数答案在需要读取的文件很大的情况下(例如,如何读取10 TB的文本文件…)会有所帮助 但我的问题有点不同,我有很多文件,比如说1亿份。我想从这些文件中读取前1-2行。该文件是10KB还是100TB无关紧要。我只需要每个文件的前一两行。因此,我希望避免读取或缓冲文件中不必要的部分。我的知识不足以彻
read()
或mmap()
。作为一个也参与了这些辩论的人,我没有找到我当前问题的答案,因为大多数答案在需要读取的文件很大的情况下(例如,如何读取10 TB的文本文件…)会有所帮助
但我的问题有点不同,我有很多文件,比如说1亿份。我想从这些文件中读取前1-2行。该文件是10KB还是100TB无关紧要。我只需要每个文件的前一两行。因此,我希望避免读取或缓冲文件中不必要的部分。我的知识不足以彻底测试哪种方法更快,也不足以首先发现我所有的选择
我现在做的是:(我现在正在做这个多线程)
在这种情况下,C++或Linux环境给了我什么?有没有一种更快或更有效的方法来读取数百万文件的一小部分
谢谢你抽出时间
信息:我可以访问
C++20
和Ubuntu 18.04您可以通过不测试路径是否为目录来保存对fstat
的一个基本调用,然后依赖是否打开
测试
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
int main()
{
std::string line,path=".";
for(const auto& p: std::filesystem::recursive_directory_iterator(path)) {
{
std::ifstream read_file(p.path().string());
if (read_file.is_open()) {
std::cout << "opened: " << p.path().string() << '\n';
while (getline(read_file, line)) {
// Get two lines here.
}
}
}
}
}
#包括
#包括
#包括
#包括
int main()
{
std::字符串行,路径=“.”;
for(const auto&p:std::filesystem::recursive\u directory\u iterator(path)){
{
std::ifstream read_文件(p.path().string());
if(read_file.is_open()){
std::cout在Linux下访问文件的程序中的任何函数都将导致调用一些“系统调用”(例如read()
)
某些编程语言中的所有其他可用函数(如fread()
,fgets()
,std::filesystem
…)调用函数或方法,这些函数或方法反过来调用一些系统调用
因此,您不能比直接调用系统调用更快
我不是100%确定,但我认为在大多数情况下,组合使用open()
,read()
,close()
将是从文件开始读取数据的最快方法
(如果数据不在文件的开头,pread()
可能比read()
快;我不确定。)
请注意,read()
不读取一定数量的行,而是读取一定数量的字节(例如,读入char
数组),因此您必须“手动”通过搜索'\n'
字符和/或char
数组中的文件结尾来查找行的结尾
不幸的是,一行可能比您预期的长得多,因此从文件中读取前N个字节并不包含前M行,您必须再次调用read()
在这种情况下,它取决于您的系统(例如,文件系统甚至硬盘)在每次调用read()
时应读取多少字节以获得最大性能
示例:假设在75%的文件中,前N行位于文件的前512字节中;在其他25%的文件中,前N行的总和超过512字节
在某些计算机上,一次读取1024字节可能需要与读取512字节几乎相同的时间,但两次读取512字节要比一次读取1024字节慢得多;在这样的计算机上,read()
1024字节:您为25%的文件节省了大量时间,而为其他75%的文件只损失了很少的时间
在其他计算机上,读取512字节要比读取1024字节快得多;在这样的计算机上,最好是read()
512字节:读取1024字节在处理25%的文件时只会节省很少的时间,但在处理其余75%的文件时会花费很多时间
我认为在大多数情况下,这个“最佳值”将是512字节的倍数,因为大多数现代文件系统以512字节的倍数组织文件。我刚刚键入了类似于Martin Rosenau的答案(当他的答案弹出时):非结构化读取的最大长度为两行。但我会更进一步:将该文本缓冲区与相应的文件名排队,然后让另一个线程解析/分析。如果解析所需时间与读取所需时间大致相同,则可以节省一半的时间。如果所需时间更长(不太可能),则可以使用多个线程并保存更多
旁注-你不应该平行阅读(尝试过)
这可能值得一试:你能打开一个文件,在继续打开下一个文件时异步读取它吗?我不知道是否有操作系统可以重叠这些内容。如果(!std::filesystem::is_directory(p))你可以去掉if(!std::filesystem::is_directory(p)){
并让ifstream
构造函数在目录中失败。这将保存一个fstat
call@Jean-弗朗索瓦·法布:ifstream
将愉快地“打开”目录…不在我的机器上,它不会给启动门带来太多的开销。在性能方面,你无法击败智能使用mmap
。解决这个问题的正确方法是在写入文件时对其进行索引。没有“快速”的方法以任何语言访问数百万个文件。我能够并行化这一点,因为文件分布在一些文件夹中(不需要先知道文件,然后在线程之间共享它们),我能够将磁盘读取量提高到6倍。但我提出这个问题的原因是,我可能从文件中读取了超出必要的内容,因此我的ssd可能会在不必要的操作上花费一些资源。想知道是否存在类似于神奇的低级系统调用(当然是更符合逻辑的调用):)Ho
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
int main()
{
std::string line,path=".";
for(const auto& p: std::filesystem::recursive_directory_iterator(path)) {
{
std::ifstream read_file(p.path().string());
if (read_file.is_open()) {
std::cout << "opened: " << p.path().string() << '\n';
while (getline(read_file, line)) {
// Get two lines here.
}
}
}
}
}