垂直遍历文件



我需要以垂直方式遍历一个文件。如果假设文件内容为:

adg
beh
cfi

它应该将文件打印为:

abc
def
ghi

每条线的长度将是相同的(即,对于上述示例,所有线的长度都为3)。我已经写了一段代码,但它没有按要求遍历文件。

#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
    fstream fs;
    fs.open("asd.txt",ios::in);
    string str;
    char *ch = new char();
    int lineLen = 0, k = 0;
    if(getline(fs,str))
    {
        lineLen = str.length();
    }
    fs.seekg(0);
    if(lineLen > 0)
    {
    for(int i = 0;i<lineLen;i++)
    {
        fs.seekg(i+k*lineLen);
        while(fs.read(ch,1))
        {
            k++;
            fs.seekg(i+k*lineLen);
            cout<<*ch;
        }
        k = 0;
    }
    }
    fs.close();
    cin.ignore();
}

我对文件处理有点陌生,找不到错误。此外,是否有更好的方法可供遵循?

在上做了一些小调整

//lines = no. of lines in file
fs.seekg(0, fs.beg);
fs.clear(); 
if(lineLen > 0)
{
for(int k = 0; k < lineLen; k++) {
    for(int i = 0;i<lines;i++){
        fs.seekg(k+i * (lineLen + 2), fs.beg); //use lines + 2
        if(fs.read (ch,1));
          cout << *ch; 
    }
   cout << endl;
}

未测试的伪代码,可能会给您一些想法。基本上,将整个文件加载到一个二维字符向量中,以便访问。它将使用比直接从文件中读取更多的内存,但这并不重要,除非文件很大。

vector<vector<char>> filemap;
string line;
while (getline(filestream, line))
{
    filemap.push_back(vector<char>(line.begin(), line.end()));
}
for (int x = 0; x < XSIZE; x++)
{
    for (int y = 0; y < YSIZE; y++)
    {
        filestream << filemap[y][x]; // note x/y are opposite way round in 2d vectors
    }
    filestream << 'n';
}

如果使用mmap(2),您可能会发现此任务要简单得多。可能有一个C++等价物或包装器,但恐怕我不是这方面的专家。如果是这样的话,希望有人能给出一个更好的答案。

下面是一个快速的C(非++)示例。我会看看我是否可以在谷歌上搜索并用C++再验证一下:

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
    int fd = open("input", O_RDONLY);
    struct stat s;
    fstat(fd, &s);
    // map the file as one big string
    char *c = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
    // calculate sizes
    int columns = strchr(c, 'n') - c; // first newline delimits a row
    int stride = columns + 1;          // count the newline!
    int rows = s.st_size / stride;     // all rows are the same length
    for (int x = 0; x < columns; x++)
    {
        for (int y = 0; y < rows; y++)
        {
            putchar(c[y*stride + x]);
        }
        putchar('n');
    }
    munmap(c, s.st_size);
    close(fd);
    return 0;
}

编辑:据我所知,在C++中快速搜索并没有找到更好的方法来处理这个问题。我的意思是,我可以在mmap行上添加一个类型转换,并将putchar调用更改为std::cout,但这似乎并没有什么区别。

与其在源文件中重复查找(),不如简单地读取整个源文件,然后从内存中的内容生成输出。

这听起来很像课堂作业,所以我不会简单地为你写答案。然而,这应该会给你指明正确的方向——中包含一些PseodoCode

为了避免疼痛,假设线路长度和最大线路的上限是安全的,即

const int MaxLines = 100;
const int MaxLength = 80;
int lineno, linelength;
// array of char pointers for each line
char *lines[] = (*lines[])malloc(Maxlines * sizeof(char*));
// ReadLoop
lineno = 0;
while (not eof)
{
  getline(buffer);
  if (++lineno++ == 1)
  {
    linelength = strlen(buffer);
  }
  else
  {
    if (linelength != strlen(buffer))
    {
      cout "Line # " << lineno << " does not match the expected length";
      exit();
    }
  } 
  lines[lineno] = malloc(strlen(buffer)+1));
  strcpy(lines[lineno], buffer);
}
int cc, linecnt = lineno;
// now all data in memory, output "vertical data"
for (cc = 0; cc < linelength; ++cc)
{
  for (lineno=0; lineno<<linelength; ++lineno)
  {
     cout << lines[xx][yy]; // xx && yy left you to figure out
  }
  cout "n";
}

如果您的文件不是很大,那么就没有理由不把整个文件拖到内存中。在C++中可能有一种更惯用的方法来实现这一点,但以下方法有效:

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
int main(int argc, char *argv[]) 
{
    std::fstream infile("foo.txt");
    std::vector<std::string> lines;
    std::string line;
    while(std::getline(infile,line)) {
        lines.push_back(line);
    }
    int m=lines.size();
    int n=lines[0].length();
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            std::cout << lines[j].at(i);
        }
        std::cout << std::endl;
    }
    return 0;
}

当然,当文件中的所有行的长度都不相同时,就会出现问题。

现在,一个"不使用任何额外内存"的版本(当然,它使用了,但不多):

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[])
{
    std::fstream infile("foo.txt");
    std::vector<std::string> lines;
    std::string line;
    std::getline(infile, line);
    int n = line.length();
    int m = 1+std::count(std::istreambuf_iterator<char>(infile),
           std::istreambuf_iterator<char>(), 'n');
    infile.clear();
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            infile.seekg(j*m+i);
            std::cout << char(infile.peek());
        }
        std::cout << std::endl;
    }
    return 0;
}

最新更新