17

有没有一种方法可以逐行向后读取文件,而不必从头开始读取文件以开始向后读取?

4

6 回答 6

15

使用内存映射文件并向后走。操作系统将以相反的顺序分页文件的所需部分。

于 2012-05-30T10:06:36.183 回答
9

根据评论,一个可能的(非常简单的)替代方案是将这些行读入vector. 例如:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

int main()
{
    std::ifstream in("main.cpp");

    if (in.is_open())
    {
        std::vector<std::string> lines_in_reverse;
        std::string line;
        while (std::getline(in, line))
        {
            // Store the lines in reverse order.
            lines_in_reverse.insert(lines_in_reverse.begin(), line);
        }
    }
}

编辑:

根据jrokLoki Astari的评论,push_back()效率会更高,但行将按文件顺序排列,因此反向迭代 ( reverse_iterator) 或std::reverse()将是必要的:

    std::vector<std::string> lines_in_order;
    std::string line;
    while (std::getline(in, line))
    {
        lines_in_order.push_back(line);
    }
于 2012-05-30T10:14:27.773 回答
4
  1. 打开文件进行读取,调用fseek()寻找文件末尾,然后调用ftell()获取文件的长度。stat()或者,您可以通过调用或获取文件长度fstat()

  2. 将缓冲区指针分配给上面 #1 中获得的文件大小。

  3. 将整个文件读入该缓冲区——您可能可以fread()一次性读取所有文件(假设文件足够小)。

  4. 使用另一个 char 指针将文件从缓冲区的末尾横向移动到缓冲区的开头。

于 2012-05-30T10:04:03.350 回答
4

稍微改进的版本是这样的:-
1)寻找最后一个位置
2)获取最后一个位置
3)读取一个字符并打印它;
4) 寻找 2 个 pos 回来;
5) 重复 3 &4last-1次;

    ifstream in;
    in.open("file.txt");
    char ch;
    int pos;
    in.seekg(-1,ios::end);
    pos=in.tellg();
    for(int i=0;i<pos;i++)
    {
        ch=in.get();
        cout<<ch;
        in.seekg(-2,ios::cur);
    }
    in.close();
于 2016-01-17T10:08:41.827 回答
3

简短的回答是否定的。但是,您可以使用 seek() 函数将指针移动到您想去的地方。然后从那个点读取()一些数据。如果你知道如何管理缓冲区,那么它应该很快,因为你可以读取和缓存数据,然后搜索前一个换行符。玩得开心 \r\n 这将被倒置......

-- 更新:对可能算法的一些阐述 --

这不是有效的代码,但它应该让您了解我在这里要说的内容

文件内容如下:

int fpos = in.size() - BUFSIZ;
char buf[BUFSIZ];
in.seek(fpos);
in.read(buf, BUFSIZ);
fpos -= BUFSIZ; // repeat until fpos < 0, although think of size % BUFSIZ != 0
// now buf has characters... reset buffer position
int bpos = BUFSIZ - 1;

获取字符串:

// first time you need to call the read
if(bpos == -1) do_a_read();
// getting string
std::string s;
while(bpos >= 0 && buf[bpos] != '\n') {
  s.insert(0, 1, buf[bpos]);
  --bpos;
}
// if bpos == -1 and buf[0] != '\n' then you need to read another BUFSIZ chars
// and repeat the previous loop...

// before leaving, skip all '\n'
while(bpos >= 0 && buf[bpos] == '\n') {
  --bpos;
}
return s;

为了简化 '\r',您可以先将所有 '\r' 转换为 '\n'。否则,'\n' 的所有测试也需要测试'\r'。

于 2012-05-30T10:01:36.413 回答
0

我的答案类似于使用 avector来存储文件行的答案,但我会改为使用list.

假设您在名为 的文件中有以下文本input.txt

hello
there
friend

我会逐行阅读文件,不是将每一行推到我的后面,list而是推到它的前面。使用它而不是push_back与将文件的内容逐行读取到 avector然后反转它或向后迭代它具有相同的效果。

#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <iterator>
#include <algorithm>

int main(void) {
    std::ifstream file;
    file.open("input.txt");
    // Make sure the file opened properly

    std::list<std::string> list;
    std::string buffer;
    while (std::getline(file, buffer)) {
        list.push_front(buffer);
    }

    file.close();

    std::copy(
        list.begin(),
        list.end(),
        std::ostream_iterator<std::string>(std::cout, "\n")
    );

    return 0;
}

(请注意,底部的位std::copy只是打印列表的内容,并使用换行符作为元素之间的分隔符。)

然后打印:

friend
there
hello
于 2019-04-05T19:32:13.747 回答