C++ 多流迭代器c++;
我的程序的目的是打开一个长度为n的m行文本文件,逐列读取文件并打印每列 例如,对于此文本文件C++ 多流迭代器c++;,c++,stream,istream-iterator,C++,Stream,Istream Iterator,我的程序的目的是打开一个长度为n的m行文本文件,逐列读取文件并打印每列 例如,对于此文本文件 abcd efgh jklm 我想打印 aej b、f、k c g l d h m 由于一行的长度可以是2000000,而列的长度可以超过10000,所以我无法在一个矩阵中打开内存中的所有文件 理论上,我希望有一个在空间使用O(m),在时间使用O(m*n)的程序 一开始,我不得不考虑以下解决方案: 如果我看到每列的所有文件,复杂性为O(m*n²) 如果我使用seekg和一个位置数组并从一个位置跳到
abcd
efgh
jklm
我想打印
aej
b、f、k
c g l
d h m
由于一行的长度可以是2000000,而列的长度可以超过10000,所以我无法在一个矩阵中打开内存中的所有文件
理论上,我希望有一个在空间使用O(m),在时间使用O(m*n)的程序
一开始,我不得不考虑以下解决方案:
- 如果我看到每列的所有文件,复杂性为O(m*n²)
- 如果我使用seekg和一个位置数组并从一个位置跳到另一个位置,那么复杂性是O(mnlog(n))
ifstream str2;
str2.open(“Input/test.data”,ifstream::in);
int nbline=3;
int-nbcolumn=4;
int x=0;
istreambuf_迭代器istart(str2);
istreambuf_迭代器iend;
istreambuf_迭代器*iarray;
iarray=新的istreambuf_迭代器[nbline];
while(istart!=iend){
如果(x%nbcolumn==0){
iarray[x/nbcolumn]=istart;
}
istart++;
x++;
}
对于(int j=0;j,您可以将任务分成多个块,然后在继续下一个块之前处理每个块
您需要为每一行(越大性能越好)和该行的查找位置设置缓冲区。您可能还需要对文件进行初始传递,以获得每一行的正确偏移量
将每行的B字节读入缓冲区(使用tellg
保存每行的位置),然后循环这些字节并生成输出。返回并读取每行的下一个B字节(使用seekg
预先设置文件位置,然后使用tellg
记住文件位置)并生成输出。重复,直到完成为止,注意最后一个块(或小输入)不要超过行的末尾
以您的示例为例,您有3行要跟踪。使用2的B大小,您可以将ab
、ef
和jk
读入3个缓冲区。循环输出aej
和bfk
。返回并读取下一个块:cd
、gh
、和lm
。这将产生cgl
和dhm
作为输出。一般注意事项 如果迭代器数组可以工作,那么它必须通过内存进行迭代(参见答案William Miller),或者它应该在哪里进行迭代 取舍是:
- 速度慢,几乎没有使用内存
- 要使用的内存很多
- 快速、合理的内存使用
- 在给定的内存(例如8 GB内存)下尽可能缩短时间
折衷方案4 需要更多关于边界条件的知识 解决方案4的概念取决于许多未知条件
- 输入数据的特征是什么?
- 一个矩阵的200T字节是多个矩阵的200T字节吗
- 要多少
- 列与行之间比率的最坏情况是什么
- 它是单个字符还是可以是单词
- 如果只是单个字符,是否可以保证每行的内存大小相同
- 如果没有,如何识别新线路
- 有多少可用RAM内存
- 目标计算机填充整个可用RAM内存的速度有多快
- 可接受的最长时间是多少
原始程序的问题分析 问题还在于:为什么它不起作用 节目
#include <fstream>
#include <string>
#include <iostream>
int main(int argc, char* argv[]) {
std::ifstream str2;
str2.open ("test.data", std::ifstream::in);
std::istreambuf_iterator<char> istart(str2);
std::istreambuf_iterator<char> iend;
std::istreambuf_iterator<char> iarray1 = istart;
istart++;
istart++;
istart++;
istart++;
std::istreambuf_iterator<char> iarray2 = istart;
std::cout << *(iarray1);
std::cout << std::endl;
std::cout << *(iarray2);
std::cout << std::endl;
return 0;
}
…程序会打印
e
e
因此,循环
while (istart != iend){
if (x % nbcolumn == 0){
iarray[x/nbcolumn] = istart;
}
istart++;
x++;
}
…不会产生预期的结果,因为迭代器以不同的方式工作,并且每次调用
iarray[i]++;
…正在同时操作所有迭代器
折衷方案3 出路是什么?根据权衡3创建代码 节目
#include <iostream>
#include <ios>
#include <string>
#include <fstream>
int main(int argc, char* argv[]) {
int nbline = 3;
int nbcolumn = 4;
std::ifstream fsIn;
std::streampos posLine[nbline];
std::streampos posTemp;
fsIn.open("test.data", std::ifstream::in);
for ( int i = 0; i < nbline; i++) {
posLine[i] = posTemp;
posTemp += nbcolumn;
}
for ( int j = 0; j < nbcolumn; j++) {
for ( int i = 0; i < nbline; i++) {
fsIn.seekg(posLine[i]);
std::cout << char(fsIn.get()) << " ";
posLine[i] = fsIn.tellg();
}
std::cout << std::endl;
}
return 0;
}
如果您想使用多个
std::istreambuf_迭代器
s执行此操作,则需要多个fstream
,以便它们执行操作,否则当您迭代一个(即istart++
)时,将影响该fstream
的所有迭代器,这意味着下次迭代一个时(即*iarray[i]你将跳过一个字符。这在解释中更清楚。考虑这个片段:
std::ifstream str;
str.open("test.data", std::ifstream::in);
std::istreambuf_iterator<char> i1 (str);
std::istreambuf_iterator<char> i2 (str);
std::cout << "i1 - " << *i1 << " i2 - " << *i2 << std::endl;
i1++;
std::cout << "i1 - " << *i1 << " i2 - " << *i2 << std::endl;
i2++;
std::cout << "i1 - " << *i1 << " i2 - " << *i2 << std::endl;
其中,i2
似乎在流中“跳过”b
。即使您稍后分配了第二个迭代器,即
std::ifstream str;
str.open("test.data", std::ifstream::in);
std::istreambuf_iterator<char> i1 (str);
std::istreambuf_iterator<char> i2;
std::istreambuf_iterator<char> iend;
int x = 0;
while (i1 != iend) {
if (x % 4 == 0) {
i2 = i1;
break;
}
x++;
i1++;
}
std::cout << *i1 << " " << *i2 << std::endl;
i1++;
std::cout << *i1 << " " << *i2 << std::endl;
i2++;
std::cout << *i1 << " " << *i2 << std::endl;
为什么?
因为在任何一种情况下,两个迭代器都作用于同一个流对象,并且每次迭代一个迭代器时,它都会从流中删除一个字符。在所讨论的代码中,每个迭代器(istart
,iarray[i]
)作用于同一个流对象,因此其中一个对象的每次迭代都会从流中删除一个char
。然后,输出很快成为未定义行为的结果,因为在流结束后的迭代是未定义的(由于迭代器一起迭代,所以您可以很快到达它)
如果您想以大纲的方式完成此操作,只需使用多个f即可
std::ifstream str;
str.open("test.data", std::ifstream::in);
std::istreambuf_iterator<char> i1 (str);
std::istreambuf_iterator<char> i2 (str);
std::cout << "i1 - " << *i1 << " i2 - " << *i2 << std::endl;
i1++;
std::cout << "i1 - " << *i1 << " i2 - " << *i2 << std::endl;
i2++;
std::cout << "i1 - " << *i1 << " i2 - " << *i2 << std::endl;
i1 - a i2 - a
i1 - b i2 - a
i1 - b i2 - c
std::ifstream str;
str.open("test.data", std::ifstream::in);
std::istreambuf_iterator<char> i1 (str);
std::istreambuf_iterator<char> i2;
std::istreambuf_iterator<char> iend;
int x = 0;
while (i1 != iend) {
if (x % 4 == 0) {
i2 = i1;
break;
}
x++;
i1++;
}
std::cout << *i1 << " " << *i2 << std::endl;
i1++;
std::cout << *i1 << " " << *i2 << std::endl;
i2++;
std::cout << *i1 << " " << *i2 << std::endl;
i1 - a i2 - a
i1 - b i2 - a
i1 - b i2 - c
#include <fstream>
#include <string>
#include <iostream>
int main(int argn, char** argv) {
std::ifstream str2;
str2.open ("test.data", std::ifstream::in);
int nbline = 3;
int nbcolumn = 4;
int x = 0;
std::istreambuf_iterator<char> istart (str2);
std::istreambuf_iterator<char> iend ;
std::ifstream* streams = new std::ifstream[nbline];
for (int ii = 0; ii < nbline; ii++) {
streams[ii].open("test.data", std::ifstream::in);
}
std::istreambuf_iterator<char>* iarray = new std::istreambuf_iterator<char>[nbline];
for (int ii = 0; ii < nbline; ii ++) {
iarray[ii] = std::istreambuf_iterator<char> (streams[ii]);
}
int idx = 0;
while (istart != iend) {
if (x % nbcolumn == 0) {
std::advance(iarray[x/nbcolumn], (nbcolumn+1)*idx);
idx++;
}
x++;
istart++;
}
for (int ii = 0; ii < nbcolumn; ii ++) {
for (int jj = 0; jj < nbline; jj ++) {
std::cout << *iarray[jj]++ << "\t";
}
std::cout << std::endl;
}
}
a e j
b f k
c g l
d h m
#include <iostream>
#include <fstream>
#include <vector>
#include <stdexcept>
#include <sstream>
#include <algorithm>
std::vector<std::size_t> getPositions(std::ifstream& str2, int &numcolumns) {
std::vector<std::size_t> iarray;
iarray.push_back(0); // Add first iterator
bool newlinereached = false;
int tmpcol = 0;
int currentLine = 0;
char currentChar = 0;
char previosChar = 0;
numcolumns = -1;
for (str2.seekg(0, std::ios_base::beg); !str2.eof(); previosChar = currentChar) {
const std::size_t currentPosition = str2.tellg();
str2.read(¤tChar, 1);
if (newlinereached) {
if (currentChar == '\r') {
// Always error but skip for now :)
continue;
}
else if (currentChar == '\n') {
// ERROR CONDITION WHEN if (numcolumns < 0) or previosChar == '\n'
continue;
}
else if (tmpcol == 0) {
throw std::runtime_error((std::stringstream() << "Line " << currentLine << " is empty").str());
}
else {
if (numcolumns < 0) {
// We just found first column size
numcolumns = tmpcol;
iarray.reserve(numcolumns);
}
else if (tmpcol != numcolumns) {
throw std::runtime_error((std::stringstream() << "Line " << currentLine
<< " have incosistend number of columns it should have been " << numcolumns).str());
}
iarray.push_back(currentPosition);
tmpcol = 1;
newlinereached = false;
}
}
else if (currentChar == '\r' || currentChar == '\n') {
newlinereached = true;
++currentLine;
}
else {
tmpcol++;
}
}
if (currentChar == 0) {
throw std::runtime_error((std::stringstream() << "Line " << currentLine
<< " contains 'null' character " << numcolumns).str());
}
str2.clear(); // Restart
return iarray;
}
int main() {
using namespace std;
ifstream str2;
str2.open("Text.txt", ifstream::in);
if (!str2.is_open()) {
cerr << "Failed to open the file" << endl;
return 1;
}
int numinputcolumns = -1;
std::vector<std::size_t> iarray =
getPositions(str2, numinputcolumns); // S(N)
const std::size_t numinputrows = iarray.size();
std::vector<char> buffer;
const int numlinestobuffer = std::min(2, numinputcolumns); // 1 For no buffer
buffer.resize(numinputrows * numlinestobuffer); // S(N)
const std::size_t bufferReadMax = buffer.size();
for (int j = 0; j < numinputcolumns; j += numlinestobuffer)
{
// Seek fill buffer. Needed because sequental reads are much faster even on SSD
// Still can be optimized more: We can buffer n+1 rows as we can discard current row read
std::size_t nread = std::min(numlinestobuffer, numinputcolumns - j);
for (int i = 0; i < numinputrows; ++i)
{
str2.seekg(iarray[i], ios_base::beg);
size_t p = str2.tellg();
str2.read(&buffer[i * numlinestobuffer], nread);
iarray[i] += nread;
}
// Print the buffer
for (int b = 0; b < nread; ++b)
{
for (int k = 0; k < numinputrows; ++k) {
std::cout << buffer[b + k * numlinestobuffer] << '\t';
}
std::cout << std::endl;
}
}
return 0;
}