17

ファイルを最初から逆方向に読み始めることなく、ファイルを1行ずつ逆方向に読み取る方法はありますか?

4

6 に答える 6

15

メモリマップトファイルを使用して、後方に移動します。OSは、ファイルの必要な部分を逆の順序でページングします。

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

編集:

jrokとLokiAstariのコメントによる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()に読み込みます。おそらく、ファイルをすべて1回で読み込むために使用できます(ファイルが十分に小さい場合)。

  4. 別のcharポインターを使用して、ファイルをバッファーの最後から最初に移動します。

于 2012-05-30T10:04:03.350 に答える
4

わずかに改善されたバージョンは次のようになります。-
1)最後の1つの位置までシークします
。2)最後の1つの位置を取得します
。3)文字を読み取って印刷します。
4)2つの位置を探します。
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();
于 2016-01-17T10:08:41.827 に答える
3

簡単な答えはノーです。ただし、seek()関数を使用して、ポインタを目的の場所に移動できます。次に、その時点からいくつかのデータをread()します。バッファの管理方法をよく知っている場合は、データを読み取ってキャッシュしてから、前の改行文字を検索できるため、非常に高速です。反転される\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

私の答えは、ファイルの行を格納するためにaを使用するものと似てvectorいますが、代わりに。を使用しlistます。

次のファイルに次のテキストがあるとしますinput.txt

hello
there
friend

私はファイルを1行ずつ読み、各行を自分の後ろではlistなく前に押していました。これを使用するのではなくpush_back、ファイルの内容を1行ずつaに読み込み、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
于 2019-04-05T19:32:13.747 に答える