0

私のプログラムはほぼ正常に動作しています。意図された目的は、ファイルを最後から読み取り、内容を宛先ファイルにコピーすることです。ただし、私を混乱させるのはlseek()方法であり、オフセットをどのように設定する必要があるかです。

src現時点での私のコンテンツは次のとおりです。
Line 1
Line 2
Line 3

現時点で宛先ファイルに表示されるのは、
Line 3
e 2
e 2... です。

私が理解していることから、呼び出しint loc = lseek(src, -10, SEEK_END);はソースファイルの「カーソル」を最後に移動し、EOFからSOFに10バイトオフセットし、locの値はオフセットを差し引いた後のファイルのサイズになります。しかし、Cの7時間後、私はここでほとんど脳死しています。

int main(int argc, char* argv[])
{
    // Open source & source file
    int src = open(argv[1], O_RDONLY, 0777);
    int dst = open(argv[2], O_CREAT|O_WRONLY, 0777);

    // Check if either reported an erro
    if(src == -1 || dst == -1)
    {
        perror("There was a problem with one of the files.");
    }

    // Set buffer & block size
    char buffer[1];
    int block;

    // Set offset from EOF
    int offset = -1;

    // Set file pointer location to the end of file
    int loc = lseek(src, offset, SEEK_END);

    // Read from source from EOF to SOF
    while( loc > 0 )
    {
        // Read bytes
        block = read(src, buffer, 1);

        // Write to output file
        write(dst, buffer, block);

        // Move the pointer again
        loc = lseek(src, loc-1, SEEK_SET);
    }

}
4

3 に答える 3

3

lseek()ファイルサイズを変更したり返したりしません。返されるのは、「カーソル」が設定されている位置です。だからあなたが電話するとき

loc = lseek(src, offset, SEEK_END);

2 回実行すると、常にカーソルが再び同じ位置に設定されます。私はあなたがこのようなことをしたいと思います:

while( loc > 0 )
{
    // Read bytes
    block = read(src, buffer, 5);

    // Write to output file
    write(dst, buffer, block);

    // Move the pointer again five bytes before the last offset
    loc = lseek(src, loc+offset, SEEK_SET);
}

行の長さが可変の場合は、代わりに次のようにすることができます。

// define an offset that exceeds the maximum line length
int offset = 256;
char buffer[256];
// determine the file size
off_t size = lseek( src, 0, SEEK_END );
off_t pos = size;
// read block of offset bytes from the end
while( pos > 0 ) {
    pos -= offset;
    if( pos < 0 ) {
        //pos must not be negative ...
        offset += pos;   // in fact decrements offset!!
        pos = 0;
    }
    lseek( src, pos, SEEK_SET );
    // add error checking here!!
    read(src, buffer, offset );
    // we expect the last byte read to be a newline but we are interested in the one BEFORE that
    char *p = memchr( buffer, '\n', offset-1 );
    p++;  // the beginning of the last line
    int len = offset - (p-buffer);  // and its length
    write( dst, p, len );
    pos -= len;            // repeat with offset bytes before the last line
}
于 2013-10-22T16:19:03.990 に答える
1

への最後の呼び出しSEEK_CURの代わりに使用する必要があると思います:SEEK_ENDlseek()

// Set file pointer location to the end of file
int loc = lseek(src, offset, SEEK_END);

// Read from source from EOF to SOF
while( loc > 0 )
{
    // Read bytes
    block = read(src, buffer, 5);

    // Write to output file
    write(dst, buffer, block);

    // Move the pointer again
    lseek(src, -10, SEEK_CUR);
}

次のこともできます。

// Set file pointer location to the end of file
int loc = lseek(src, offset, SEEK_END);

// Read from source from EOF to SOF
while( loc > 0 )
{
    // Read bytes
    block = read(src, buffer, 5);

    // Write to output file
    write(dst, buffer, block);

    // Move the pointer again
    loc -= 5;
    lseek(src, loc, SEEK_SET);
}
于 2013-10-22T16:16:25.000 に答える
1

いくつかのコメントから、テキスト ファイルのの順序を逆にしたいようです。残念ながら、このような単純なプログラムではそれを実現することはできません。取得したい複雑さ、ファイルの大きさ、手元にあるメモリの量、必要な速度などに応じて、いくつかの方法があります。

ここに私の頭の上のいくつかの異なるアイデアがあります:

  • ソース ファイル全体を一度に 1 つのメモリ ブロックに読み込みます。メモリ ブロックを順方向にスキャンして改行を探し、各行のポインターと長さを記録します。これらのレコードをスタックに保存し (動的配列または C++ の STL ベクトルを使用できます)、出力ファイルを書き込むには、行のレコードをスタックからポップし (配列を逆方向に移動します)、次の値になるまで書き込みます。スタックが空です (配列の先頭に到達しました)。

  • 入力ファイルの末尾から開始しますが、各行について、前の行を開始する改行が見つかるまで、1 文字ずつ後方にシークします。その改行を過ぎて再び前方にシークし、その行を読み取ります。(これで、その長さがわかるはずです。) または、反転した文字をバッファーに蓄積してから、それらを逆方向に書き出すこともできます。

  • ファイルのブロック全体 (おそらくセクター) を、最初から最後まで一度に取り込みます。各ブロック内で、上記の方法と同様の方法で改行を見つけます。ただし、文字は既にメモリ内にあるため、それらを元に戻したり冗長に引っ張ったりする必要はありません。ただし、このソリューションは、行がブロックの境界をまたぐ可能性があるため、はるかに複雑になります。

より精巧で巧妙なトリックがあるかもしれませんが、それらはより明白で単純なアプローチです。

于 2013-10-22T17:22:00.200 に答える