繁体   English   中英

C将文件内容从EOF复制到SOF

[英]C copy file contents from EOF to SOF

我的程序几乎可以正常工作。 预期目的是从头读取文件,然后将内容复制到目标文件。 但是,令我困惑的是lseek()方法,所以我应该如何设置偏移量。

我目前的src内容是:
1号线
2号线
3号线

目前,我在目标文件中得到的是:
3号线
2号
e 2 ...

据我了解,调用int loc = lseek(src, -10, SEEK_END); 将源文件中的“光标”移动到结束,然后将其从EOF偏移到SOF 10个字节,而loc的值将是我减去偏移后的文件大小。 但是,经过7个小时的C,我在这里几乎死了。

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

}

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
}

我想你应该使用SEEK_CUR ,而不是SEEK_END在您的最终调用lseek()

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

从您的一些评论看来,您想要颠倒文本文件中各的顺序。 不幸的是,您不会通过这样一个简单的程序来实现这一点。 您可以采取几种方法,具体取决于您要变得多么复杂,文件有多大,手头有多少内存,想要多快等。

这是我想到的一些不同的想法:

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

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

  • 从头到尾一次拉入整个文件块(可能是扇区)。 在每个块中,以与上述方法类似的方式定位换行符,除了现在您已经在存储器中存储了字符,因此无需进行任何反向或多余地拉入字符。 但是,此解决方案将更加复杂,因为行可以跨越块边界。

可能会有更多精心设计/巧妙的把戏,但这是更明显,直接的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM