C++ 向后读取文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10813930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:29:39  来源:igfitidea点击:

Read a file backwards?

c++

提问by mezamorphic

Is there a way to read a file backwards, line by line, without having to go through the file from the beginning to start reading backwards?

有没有办法逐行向后读取文件,而不必从头开始读取文件?

采纳答案by hmjd

As per comment, a possible (quite simple) alternative would be read the lines into a vector. For example:

根据评论,一个可能的(非常简单的)替代方法是将这些行读入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);
        }
    }
}

EDIT:

编辑:

As per jrok's and Loki Astari's comments, push_back()would be more efficient but the lines would be in file order, so reverse iteration (reverse_iterator) or std::reverse()would be necessary:

根据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);
    }

回答by Roger Lipscombe

Use a memory-mapped fileand walk backwards. The OS will page in the needed parts of the file in reverse order.

使用内存映射文件并倒退。操作系统将以相反的顺序在文件的所需部分中分页。

回答by Tejendra

  1. Open the file for read, call fseek()to seek to the end of the file, then call ftell()to get the length of the file. Alternatively you can get the file length by calling stat()or fstat()

  2. Allocate a buffer pointer to the file size obtained in #1, above.

  3. Read the entire file into that buffer -- you can probably use fread()to read the file all in one shot (assuming the file is small enough).

  4. Use another char pointer to transverse the file from end to beginning of the buffer.

  1. 打开文件进行读取,调用fseek()seek到文件末尾,然后调用ftell()获取文件长度。或者,您可以通过调用stat()fstat()

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

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

  4. 使用另一个字符指针从缓冲区的末尾到开头遍历文件。

回答by Alexis Wilke

The short answer would be no. However, you can use the seek() function to move your pointer to where you want to go. Then read() some data from that point. If you know well how to manage buffers, then it should be pretty quick because you can read and cache the data and then search for the previous newline character(s). Have fun with \r\n which will be inverted...

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

-- Update: some elaboration on the possible algorithm --

-- 更新:对可能算法的一些详细说明 --

This is not valid code, but it should give you an idea of what I'm trying to say here

这不是有效的代码,但它应该让您了解我在这里想说什么

File reads:

文件写道:

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;

Getting string:

获取字符串:

// 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;

To ease with '\r', you could have a first pass that transforms all '\r' to '\n'. Otherwise, all the tests of '\n' need to also test for '\r'.

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

回答by Aadhil RF

Slightly improved version will be this:-
1)Seek to the last-1 position
2)Get the last-1 position
3)Read a char and print it;
4)seek 2 pos back;
5)repeat 3 &4 for last-1times;

稍微改进的版本将是这样的:-
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();

回答by Personage

My answer is similar to ones that use a vectorto store the lines of the file, but I would instead use a list.

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

Imagine you have the following text in a file called input.txt:

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

hello
there
friend

I would read the file line-by-line, pushing each line not to the back of my listbut to its front. Using this rather than push_backhas the same effect as reading the contents of the file line-by-line into a vectorand then reversing it or iterating through it backwards.

我会逐行阅读文件,将每一行都推到我的后面而不是list它的前面。使用 this 而不是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;
}

(Note that the bit at the bottom with std::copyis just to print the contents of the list with a newline character as a delimiter between elements.)

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

This then prints:

然后打印:

friend
there
hello