如何用C++部分地获取文件中的行

How to get line in a file partially by C++

本文关键字:文件 获取 何用 C++      更新时间:2023-10-16

我想部分读取输入文件中的数据。例如,输入文件是1GB,我想每次只读取100MB,然后存储在矢量中。如何在第一个循环后继续阅读下一行?正如你在下面的代码中看到的,在i的第一个循环之后,向量v可能存储了输入文件中的1000行。我不确定I的下一个循环,while命令(std::getline(infile,line((是否会继续从输入文件的第1001行读取?如果没有,我如何修改我的代码以从几个组(1~1000(、(1001~2000(、(2001~3000(的输入中获取行。。。那么存储在向量v中?

#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 filen";           
}
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();

我没有耐心检查整个代码。从头开始写拆分器比较容易。总之,以下是一些观察结果:

std::ifstream infile;
if (!infile.is_open())
{
std::cout << "Unable to open filen";
}
infile.open(infilepath, std::ifstream::in);

您将始终收到消息,因为您在打开文件之前检查了。打开文件的一种正确方法是:

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;

为什么在生成结果文件之前需要结果文件的数量?您永远无法正确计算它,因为它取决于行的长度(您不能仅仅为了将行的一半放入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();
}