C++ 多流迭代器c++;

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和一个位置数组并从一个位置跳到

我的程序的目的是打开一个长度为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和一个位置数组并从一个位置跳到另一个位置,那么复杂性是O(mnlog(n))
最后一点,对于一些服务器问题,我只需要使用STL

我的最后一个想法是创建一个文件的迭代器数组,并在每行的开头初始化这些迭代器。之后,为了查看下一列,我只需要增加每个迭代器。这是我的密码

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),或者它应该在哪里进行迭代

取舍是:

  • 解析直到第一个输出行完成,而所有其他输出行的解析都是相同的
    • 速度慢,几乎没有使用内存
  • 完全填充矩阵并输出转置矩阵
    • 要使用的内存很多
  • 为所有输出线创建位置数组,通过所有位置进行搜索
    • 快速、合理的内存使用
  • 方法2和方法3非常智能的混合。
    • 在给定的内存(例如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(&currentChar, 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;
    }