【问题标题】:Read a file backwards?向后读取文件?
【发布时间】:2012-05-30 09:53:41
【问题描述】:

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

【问题讨论】:

  • 您可以将文件的行读入vector 并反转它。
  • @hmjd 这应该是一个答案,IMO。

标签: c++


【解决方案1】:

使用memory-mapped file 并向后走。操作系统将以相反的顺序分页文件的所需部分。

【讨论】:

  • 这也是一个想法,尽管映射文件通常并不完全直接(尤其是第一次!)
【解决方案2】:

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

编辑:

根据jrok's 和Loki Astari's cmets,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);
    }

【讨论】:

  • 您可以在读取完成后使用std::reverse,也可以使用reverse_iterator 进行迭代。
  • @jrok,代码按原样插入到向量的前面,因此这些行已经是相反的顺序,因此不需要任何形式的反转。如果使用了push_back,那么是的,使用一种反向的形式。
  • 我猜测将搜索移动到文件的后面然后向前迭代会更好的性能吗?
  • @hmjd 是的,我这么说是因为我想组合 os push_backs 后跟 reverse 会更快。
  • 不,您需要使用reverse_iteratorstd::reverse(lines_in_order.begin(), lines_in_order.end()); 然后iterator
【解决方案3】:
  1. 打开文件进行读取,调用fseek()查找文件末尾,然后调用ftell()获取文件长度。或者,您可以通过调用 stat()fstat()

  2. 来获取文件长度
  3. 分配一个缓冲区指针,指向上面 #1 中获得的文件大小。

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

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

【讨论】:

  • 假设文件可以轻松放入内存中,这是一个很好、简单的解决方案。
【解决方案4】:

稍微改进的版本是这样的:-
1)寻找到最后一个位置
2) 获得最后 1 个位置
3)读取一个字符并打印它;
4) 寻找 2 个 pos 回来;
5) 重复 3 &4 last-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();

【讨论】:

    【解决方案5】:

    简短的回答是否定的。但是,您可以使用 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'。

    【讨论】:

    • @user1107474:“逐行”只是将\r\n 字节解释为换行符的问题。如果您向后读取字节,并自己解释换行字节,您当然可以向后读取行。这不是标准功能。
    • 这里有一点注意...... s.insert(0, 1, char) 很慢。如果您想加快速度,您需要保存结束点(输入 while 之前的 bpos)和起始点(输入 while 之后的 bpos)并立即将该字符串添加到结果中。
    【解决方案6】:

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

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

    hello
    there
    friend
    

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

    #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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-27
      • 1970-01-01
      • 2013-01-27
      • 2011-10-18
      相关资源
      最近更新 更多