2

私は tail 関数の実装に取り​​組んread()write()おりlseek()、I/O には と のみを使用することになっています。これまでのところ、次のようになっています。

int printFileLines(int fileDesc)
{
    char c; 
    int lineCount = 0, charCount = 0;   
    int pos = 0, rState;
    while(pos != -1 && lineCount < 10)
    {
        if((rState = read(fileDesc, &c, 1)) < 0)
        {
            perror("read:");
        }
        else if(rState == 0) break;
        else
        {
            if(pos == -1)
            {
                pos = lseek(fileDesc, 0, SEEK_END);
            }
            pos--;
            pos=lseek(fileDesc, pos, SEEK_SET); 
            if (c == '\n')
            {
                lineCount++;
            }
            charCount++;
        }
    }

    if (lineCount >= 10)
        lseek(fileDesc, 2, SEEK_CUR);
    else
        lseek(fileDesc, 0, SEEK_SET);

    char *lines = malloc(charCount - 1 * sizeof(char));

    read(fileDesc, lines, charCount);
    lines[charCount - 1] = 10;
    write(STDOUT_FILENO, lines, charCount);

    return 0;
}

これまでのところ、10行を超えるファイルでは機能しますが、10行未満のファイルを渡すとブレーキがかかり、そのファイルの最後の行を出力するだけで、stdin. 誰かがこの問題を解決する方法を教えてくれたら、それは素晴らしいことです:D

4

1 に答える 1

2

最初の問題:

ここで改行を読むと……

if(read(fileDesc, &c, 1) < 0)
{
    perror("read:");
}

...そして、その改行の前の文字に直接位置を設定します...

pos--;
pos=lseek(fileDesc, pos, SEEK_SET);

次にlinecountis >= 10(while ループが終了) の場合、最初に読み取った文字は、最後の改行の前の行の最後の文字です。改行自体も最後の 10 行の一部ではないため、現在のストリーム位置から 2 文字をスキップします。

if (linecount >= 10)
    lseek(fileDesc, 2, SEEK_CUR);

2番目の問題について:

ストリーム オフセットがストリームの先頭に到達したと仮定します。

pos--;
pos=lseek(fileDesc, pos, SEEK_SET); // pos is now 0

while 条件はまだ TRUE です。

while(pos != -1 && lineCount < 10)

これで char が読み取られます。この後、ファイル オフセットは1 (2 番目の文字) です。

if(read(fileDesc, &c, 1) < 0)
{
    perror("read:");
}

ここでは、pos が -1 に低下し、lseek が失敗します。

pos--;
pos=lseek(fileDesc, pos, SEEK_SET); 

lseek が失敗したため、ファイル内の位置は2 番目の文字になり、最初の文字が欠落しています。pos == -1while ループの後にファイル オフセットをファイルの先頭にリセットすることで、これを修正します。

if (linecount >= 10)
    lseek(fileDesc, 2, SEEK_CUR);
else
    lseek(fileDesc, 0, SEEK_SET);

パフォーマンス:

これには非常に多くのシステムコールが必要です。簡単な拡張は、バッファリングされた f* 関数を使用することです。

FILE *f = fdopen(fileDesc, "r");
fseek(...);
fgetc(...);

など。さらに、これにはシステム固有の機能は必要ありません。

ファイルをチャンクごとに逆方向に読み取り、これらのチャンクで操作する方がさらに良いでしょうが、これにはさらにコーディング作業が必要です。

Unix の場合、mmap()ファイル全体をメモリ内で後方検索して改行文字を検索することもできます。

于 2016-01-18T19:26:35.013 に答える