簡體   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