垂直遍历文件

时间:2013-08-30 16:54:04

标签: c++

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

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

我对文件处理有点新意,无法找到错误。此外,是否有更好的方法可以遵循这一点?

6 个答案:

答案 0 :(得分:2)

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

这是一个快速的C(不是++)示例。我会看看我是否可以谷歌和C ++ ify更多:

#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;
}

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

答案 1 :(得分:1)

未经测试的伪代码可能会给你一些想法。基本上,将整个文件加载到2d字符向量中以便于访问。它将使用比直接从文件中读取更多的内存,但除非文件非常大,否则无关紧要。

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';
}

答案 2 :(得分:1)

不是尝试在源文件中重复搜索(),而是简单地读取整个源文件然后从内存中的内容生成输出,这样更容易,更快。

这听起来很糟糕,就像课堂作业一样,所以我不会简单地为你写答案。但是,这应该指向正确的方式 - 包括一些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";
}

答案 3 :(得分:1)

通过一些小调整来实现你的方式

//lines = no. of lines in file
fs.seekg(0,fs.beg);
fs.clear(); 
if(lineLen > 0)
{
for(;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;
}

答案 4 :(得分:0)

你可以将所有行重新编入一个列表然后迭代两个循环并打印字符,第一个循环遍历单词的长度,第二个循环遍历文本文件的行。所以你将在每次迭代时打印每行的一个字符。

这是一个示例代码(虽然在c中仅使用字符串数组)

void print_vertically() {
    const char* lines[3];
    lines[0] = "adg";
    lines[1] = "beh";
    lines[2] = "cfi";

    int num_lines = 3;
    int max_len = 3;

    for(int i = 0; i < max_len; i++) {
        for(int j = 0; j < num_lines; j++) {
            if(i < strlen(lines[j])) { // strlen in a loop should be avoided 
                                       // since it runs through all the chars of
                                       // a string to count the length
                printf("%c", lines[j][i]);
            } else {
                printf(" ");
            }
        }
        printf("\n");
    }
}

<强>输出

abc
def
ghi

答案 5 :(得分:0)

如果您的文件不是很大,那么没有理由不将整个内容淹没在内存中。在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;
}