简体   繁体   English

如何使用C ++中的流读取文件末尾的给定行数?

[英]How do I read a given number of lines from the end of the file using streams in C++?

For my implementation of tail shell command in Linux, I need to read certain amount of lines/bytes from the end of the file using stream input/output. 对于我在Linux中实现tail shell命令,我需要使用流输入/输出从文件末尾读取一定量的行/字节。 Does anyone have suggestions how to do that? 有人有建议怎么做吗? I suspect I need to open a file and pass some parameter to the ifstream constructor, but I don't know what exactly. 我怀疑我需要打开一个文件并将一些参数传递给ifstream构造函数,但我不知道究竟是什么。 Googling didn't find anything. 谷歌搜索没有找到任何东西。

由于tail需要使用管道,你不能倒带,你必须保留你读过的最后n行的旋转缓冲区,你将在EOF上转储。

This problem is analogous to the problem of getting the last n nodes of a singly-linked list. 这个问题类似于获取单链表的最后n节点的问题。 You have to go all the way to the end with a buffer of n lines, then spit out the lines from buffer. 你必须使用n行的缓冲区一直到最后,然后从缓冲区吐出行。

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int main()
{
  ifstream is("file.txt", ios::binary);
  if (!is) {
    cout << "Failed to open file" << endl;
    return 1;
  }

  is.seekg(0, ios::end);
  int len = is.tellg();
  char c;
  int n = 0;
  ostringstream line;
  int lines = 0;

  for (int i = len - 1; i >= 0; --i) {
    is.seekg(i, ios::beg);
    is.get(c);
    if (c == '\n' || i == 0) {
      if (i < len - 1) {
        if (i == 0) {
          line << c;
        }
        string s = line.str();
        cout << lines << ": " << string(s.rend() - n, s.rend()) << endl;
        ++lines;
        n = 0;
        line.seekp(0, ios::beg);
      }
    } else {
      line << c;
      ++n;
    }
  }

  is.close();

  return 0;
}

I don't think there's an easy way to go about this, you'll probably need to seek to the end of the file, back up one 'chunk' (an arbitrary size, but a couple of kilobytes perhaps), read that 'chunk' of data and start looking through it for new line characters, if you didn't find enough, you back up twice your chunk size (remember, you read forward, so you need to back up the one you read, plus the one you want to read next), and read in another one. 我不认为有一个简单的方法可以解决这个问题,你可能需要寻找文件的末尾,备份一个'块'(任意大小,但也许几千字节),读到'大块的数据,并开始查找新行字符,如果你找不到足够的,你备份你的块大小两倍(记住,你向前看,所以你需要备份你读的那个,加上一个你想读下一篇),然后读另一篇。

HTH HTH

this shows how you'd do it in c++... read successive chunks from the end of the file, then scan the chunks for new lines. 这显示了如何在c ++中执行...从文件末尾读取连续的块,然后扫描块以获取新行。 if a newline isn't found, part of the chunk has to be kept around and combined with the next chunk read in... 如果找不到换行符,则必须保留部分块并与下一个块读取相结合...

//
// USAGE: lastln COUNT [FILE]
//
// Print at most COUNT lines from the end of FILE or standard input.
// If COUNT is -1, all lines are printed.
//

#include <errno.h>
#include <libgen.h>
#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int main(int argc, char **argv)
{
  int ret = 0, maxLines = -1, len, count = 0, sz = 4096, lines = 0, rd;
  istream *is;
  ifstream ifs;
  stringstream ss;
  char *buf = NULL;
  const char *prog = (argc > 0 && argv[0] ? basename(argv[0]) : "");
  string line;

  if (argc > 1) {
    if ((maxLines = atoi(argv[1])) == 0) {
      goto end;
    }
  }

  if (argc > 2 && !(argv[2] && argv[2][0] == '-' && argv[2][1] == '\0')) {
    ifs.open(argv[2], ios::in | ios::binary);
    if (!ifs) {
      ret = 1;
      cerr << prog << ": " << argv[2] << ": " << strerror(errno) << endl;
      goto end;
    }
    is = &ifs;
  } else {
    ss << cin.rdbuf();
    if (!ss) {
      ret = 1;
      cerr << prog << ": failed to read input" << endl;
      goto end;
    }
    is = &ss;
  }

  is->seekg(0, ios::end);
  len = is->tellg();
  buf = new char[sz + 1];

  while (rd = min(len - count, sz)) {
    is->seekg(0 - count - rd, ios::end);
    is->read(buf, rd);
    count += rd;
    char *p = buf + rd, *q;
    *p = '\0';

    for (;;) {
      q = (char *)memrchr(buf, '\n', p - buf);
      if (q || count == len) {
        if (q) *q = '\0';
        if (lines || p - q - 1 > 0 || !q) {
          ++lines;
          cout << lines << ": " << (q ? q + 1 : buf) << line << endl;
          line.clear();
          if (lines >= maxLines && maxLines != -1) break;
        }
        if (q) p = q; else break;
      } else {
        line = string(buf, p - buf) + line;
        break;
      }
    }
  }

  end:

  if (buf) delete[] buf;
  return ret;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM