C++ 如何通过C++;
我想部分读取输入文件中的数据。例如,输入文件是1GB,我希望每次只读取100MB,然后存储在向量中。在第一个循环之后,我如何继续阅读下一行?正如您在下面的代码中所看到的,在i的第一个循环之后,可能向量v从输入文件中存储了1000行。我不确定I的下一个循环,即while命令(std::getline(infle,line))是否将继续从输入文件的第1001行读取?如果没有,我如何修改我的代码以从几个组(1~1000)、(1001~2000)、(2001~3000)的输入中获取行。。。然后存储在向量v中C++ 如何通过C++;,c++,vector,fstream,stdvector,getline,C++,Vector,Fstream,Stdvector,Getline,我想部分读取输入文件中的数据。例如,输入文件是1GB,我希望每次只读取100MB,然后存储在向量中。在第一个循环之后,我如何继续阅读下一行?正如您在下面的代码中所看到的,在i的第一个循环之后,可能向量v从输入文件中存储了1000行。我不确定I的下一个循环,即while命令(std::getline(infle,line))是否将继续从输入文件的第1001行读取?如果没有,我如何修改我的代码以从几个组(1~1000)、(1001~2000)、(2001~3000)的输入中获取行。。。然后存储在向量
#define FILESIZE 1000000000 // size of the file on disk
#define TOTAL_MEM 100000 // max items the memory buffer can hold
void ExternalSort(std::string infilepath, std::string outfilepath)
{
std::vector<std::string> v;
int runs_count;
std::ifstream infile;
if(!infile.is_open())
{
std::cout << "Unable to open file\n";
}
infile.open(infilepath, std::ifstream::in);
if(FILESIZE % TOTAL_MEM > 0)
runs_count = FILESIZE/TOTAL_MEM + 1;
else
runs_count = FILESIZE/TOTAL_MEM;
// Iterate through the elements in the file
for(i = 0; i < runs_count; i++)
{
// Step 1: Read M-element chunk at a time from the file
for (j = 0; j < (TOTAL_MEM < FILESIZE ? TOTAL_MEM : FILESIZE); j++)
{
while(std::getline(infile, line))
{
// If line is empty, ignore it
if(line.empty())
continue;
new_line = line + "\n";
// Line contains string of length > 0 then save it in vector
if(new_line.size() > 0)
v.push_back(new_line);
}
}
// Step 2: Sort M elements
sort(v.begin(), v.end()); //sort(v.begin(), v.end(), compare);
// Step 3: Create temporary files and write sorted data into those files.
std::ofstream tf;
tf.open(tfile + ToString(i) + ".txt", std::ofstream::out | std::ofstream::app);
std::ostream_iterator<std::string> output_iterator(tf, "\n");
std::copy(v.begin(), v.end(), output_iterator);
v.clear();
//for(std::vector<std::string>::iterator it = v.begin(); it != v.end(); ++it)
// tf << *it << "\n";
tf.close();
}
infile.close();
#定义文件大小100000000//磁盘上文件的大小
#定义内存缓冲区可容纳的项目总数\u MEM 100000//max
void ExternalSort(标准::字符串填充路径,标准::字符串输出路径)
{
std::向量v;
int运行u计数;
std::ifstream-infle;
如果(!infle.is_open())
{
标准::cout(0)
运行\u count=FILESIZE/TOTAL\u MEM+1;
其他的
运行\u count=FILESIZE/TOTAL\u MEM;
//遍历文件中的元素
对于(i=0;i0)
v、 向后推_(新_线);
}
}
//步骤2:对M个元素进行排序
排序(v.begin(),v.end());//排序(v.begin(),v.end(),比较);
//步骤3:创建临时文件并将排序后的数据写入这些文件。
std::流tf;
打开(tfile+ToString(i)+“.txt”,std::ofstream::out | std::ofstream::app);
std::ostream_迭代器输出_迭代器(tf,“\n”);
复制(v.begin(),v.end(),输出迭代器);
v、 清除();
//对于(std::vector::iterator it=v.begin();it!=v.end();++it)
//tf我没有耐心检查整个代码。从头开始编写拆分器更容易。无论如何,下面是一些观察结果:
例如,即使对于不存在的文件也是如此。该算法也适用于空文件
为什么在生成它们之前需要生成文件的数量?你永远无法正确计算,因为它取决于行的长度(你不能仅仅为了将行的一半放入TOTAL_MEM
),你应该从输入文件中读取最多TOTAL_MEM
字节(但至少是一行),排序并保存,然后从您离开的位置继续(请参阅下面execute
中的循环)
在第一个循环之后,我如何继续阅读下一行
如果不关闭输入流,下一次读取将从您离开的地方继续
解决方案:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
std::vector<std::string> split_file(const char* fn, std::size_t mem); // see the implementation below
int main()
{
const std::size_t max_mem = 8;
auto r = split_file("input.txt", max_mem);
std::cout << "generated files:" << std::endl;
for (const auto& fn : r)
std::cout << fn << std::endl;
}
class split_file_t
{
public:
split_file_t(std::istream& is, std::size_t mem) :is_{ is }, mem_{ mem }
{
// nop
}
std::vector<std::string> execute()
{
while (make_file())
;
return std::move(ofiles_);
}
protected:
std::istream& is_;
std::size_t mem_;
std::vector<std::string> ofiles_;
static std::string make_temp_file()
{
std::string fn(512, 0);
tmpnam_s(&fn.front(), fn.size()); // this might be system dependent
std::ofstream os(fn);
os.close();
return fn;
}
bool make_file()
{
using namespace std;
// read lines
vector<string> lines;
{
streamsize max_gpos = is_.tellg() + streamsize(mem_);
string line;
while (is_.tellg() < max_gpos && getline(is_, line))
lines.push_back(line);
}
//
if (lines.empty())
return false;
// sort lines
sort(lines.begin(), lines.end());
// save lines
{
string ofile = make_temp_file();
ofstream os{ ofile };
if (!os)
throw "could not open output file";
copy(lines.begin(), lines.end(), ostream_iterator<string>(os, "\n"));
ofiles_.push_back(ofile);
}
//
return bool(is_);
}
};
std::vector<std::string> split_file(const char* fn, std::size_t mem)
{
using namespace std;
ifstream is{ fn };
if (!is)
return vector<string>();
return split_file_t{ is, mem }.execute();
}
#包括
#包括
#包括
#包括
#包括
#包括
std::vector split_file(const char*fn,std::size_t mem);//参见下面的实现
int main()
{
常数std::size\u t max\u mem=8;
auto r=拆分文件(“input.txt”,max\u mem);
std::不清楚问题是什么-您没有在循环中关闭infle,因此任何后续读取都将从最后一个位置继续。仅供参考,if(new_-line.size()>0)
-是没有意义的。您已经从前两行确定它不会为空。事实上,前一行保证new_-line.size()>0
总是正确的。正如cup指出的,while(std::getline(infle,line))
循环将消耗整个输入文件,无论您是否喜欢。您的语句是,“在i的第一个循环之后,向量v可能存储了输入文件中的1000行。”为false。没有其他条件可以打破这一点,因此您跳过的所有剩余for循环箍最终都是毫无意义的。@cup我想确保数据存储在输出文件(tf1、tf2…)中随后从输入文件获取数据行。例如,tf1从1~1000获取行,tf2从1001~2000获取行……但我不确定当前代码版本是否总是将1~1000的输入行存储到所有输出文件中,或者它是否会像我预期的那样生成。@HectorTa“我不确定当前代码版本是否总是存储1~1000的输入行”查看代码。它会消耗整个输入文件,将所有非空行填充到v
中。然后对它们进行排序,并将整个内容转储到当前输出文件中。由于您尚未提供v
的定义位置,其他输入文件将(a)如果v在外部for循环内具有作用域,则为空,或(b)如果v
的作用域超出外部for循环,则包含实际读取输入文件的第一个过程中的重复完整数据。@WhozCraig:我编辑了上面的代码,请帮助我检查。文件大小为200GB,RAM 8GB。因此我们无法一次读取输入文件中的所有行。这就是为什么我需要将输入数据分成几个部分并存储在中多个输出文件。因此,我的代码只能为所有输出文件获取重复数据?如何使输出文件存储数据而不重复?例如,output1存储输入文件中的输入行1~1000,output2存储输入文件中的行1001~2000。在(std::getline(infle,line))时不必关心命令,可能我们需要使用另一个命令来执行此任务。但我不知道如何使用。谢谢。但是#包括什么?编译器在那一行显示错误。即使在我删除它之后,在tmpnam_s(&fn.front(),fn.size())上也出现了另一个错误;您
std::ifstream infile(infilepath);
if (!infile)
throw "could not open the input file";
if (infile.peek() == std::ifstream::traits_type::eof())
if(FILESIZE % TOTAL_MEM > 0)
runs_count = FILESIZE/TOTAL_MEM + 1;
else
runs_count = FILESIZE/TOTAL_MEM;
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
std::vector<std::string> split_file(const char* fn, std::size_t mem); // see the implementation below
int main()
{
const std::size_t max_mem = 8;
auto r = split_file("input.txt", max_mem);
std::cout << "generated files:" << std::endl;
for (const auto& fn : r)
std::cout << fn << std::endl;
}
class split_file_t
{
public:
split_file_t(std::istream& is, std::size_t mem) :is_{ is }, mem_{ mem }
{
// nop
}
std::vector<std::string> execute()
{
while (make_file())
;
return std::move(ofiles_);
}
protected:
std::istream& is_;
std::size_t mem_;
std::vector<std::string> ofiles_;
static std::string make_temp_file()
{
std::string fn(512, 0);
tmpnam_s(&fn.front(), fn.size()); // this might be system dependent
std::ofstream os(fn);
os.close();
return fn;
}
bool make_file()
{
using namespace std;
// read lines
vector<string> lines;
{
streamsize max_gpos = is_.tellg() + streamsize(mem_);
string line;
while (is_.tellg() < max_gpos && getline(is_, line))
lines.push_back(line);
}
//
if (lines.empty())
return false;
// sort lines
sort(lines.begin(), lines.end());
// save lines
{
string ofile = make_temp_file();
ofstream os{ ofile };
if (!os)
throw "could not open output file";
copy(lines.begin(), lines.end(), ostream_iterator<string>(os, "\n"));
ofiles_.push_back(ofile);
}
//
return bool(is_);
}
};
std::vector<std::string> split_file(const char* fn, std::size_t mem)
{
using namespace std;
ifstream is{ fn };
if (!is)
return vector<string>();
return split_file_t{ is, mem }.execute();
}