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

两次它总是将光标再次设置到相同的位置。我猜你想做这样的事情:

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

从您的一些评论来看,您似乎想要颠倒文本文件中行的顺序。不幸的是,你不会用这样一个简单的程序来做到这一点。您可以采用多种方法,具体取决于您想要获得的复杂程度、文件有多大、手头有多少内存、您希望它有多快等等。

以下是我脑海中的一些不同想法:

  • 一次将整个源文件读入单个内存块。向前扫描内存块以查找换行符并记录每行的指针和长度。将这些记录保存到堆栈中(您可以使用动态数组或 C++ 中的 STL 向量),然后写入输出文件,只需将行的记录从堆栈中弹出(向后移动数组)并写入直到堆栈为空(您已到达数组的开头。)

  • 从输入文件的末尾开始,但对于每一行,逐个字符向后查找,直到找到开始一行的换行符。越过该换行符再次向前搜索,然后读入该行。(您现在应该知道它的长度。)或者,您可以在缓冲区中构建反转的字符,然后将它们向后写出。

  • 从头到尾一次拉入文件的整个块(也许是扇区)。在每个块中,以与上述方法类似的方式定位换行符,除了现在您已经在内存中拥有字符,因此不需要进行任何反转或冗余地拉入它们。然而,这个解决方案会复杂得多,因为线可以跨越块边界。

可能有更复杂/更聪明的技巧,但这些是更明显、更直接的方法。

于 2013-10-22T17:22:00.200 回答
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 回答