2012-01-27 60 views
15

我已經編寫了一個程序,它將一個文件作爲輸入,並且每當找到長度大於80的行時,就會將\和\ n添加到該文件中文件,使其80個字符的寬度最大。C函數在文件中的特定位置插入文本而不覆蓋現有文本

問題是,我已經使用fseek插入\和\ n每當長度超過80,所以它覆蓋該行超過長度80的兩個字符。有沒有一種方法,我可以插入文本而不覆蓋現有的文字?

這裏是我的代碼: -

#include<stdio.h> 
#include<string.h> 

int main(int argc, char *argv[]) 
{ 
    FILE *fp1,*fp2; 
    int prev=0,now=0; 
    char ch; 
    int flag=0; 
    long cur; 
    fp1=fopen(argv[1],"r+"); 
    if(fp1==NULL){ 
    printf("Unable to open the file to read. Program will exit."); 
    exit(0); 
    } 
    else{ 
    while((ch=fgetc(fp1))!=EOF){ 
     if(ch!=' ' && ch!='\n'){ 
     now=now+1; 
     } 
     else{ 
     if(now>=80){ 
      fseek(fp1,cur,SEEK_SET); 
      fputc('\\',fp1); 
      fputc('\n',fp1); 
      now=0; 
      continue; 
     } 
     if(ch=='\n'){ 
      flag=0; 
      now=0; 
      continue; 
      } 
     else{ 
      prev=now; 
      cur=ftell(fp1); 
     } 
     now=now+1; 
     } 
    } 
    } 
    fclose(fp1); 
    return 0; 
} 

要運行它,你需要做以下幾點: -

[email protected]$ cc xyz.c 
[email protected]$ ./a.out file_to_check.txt 
+2

不,沒有,沒有將數據插入到t中的方法他中間的一個文件。您需要自己處理「移動」數據,和/或寫入新文件。 – Mat 2012-01-27 12:10:17

+1

@Mat:我會將您的評論標記爲「不是評論」,因爲它是一個答案:) – 2012-01-27 12:10:58

+2

可能的重複[如何在文件中間插入和刪除某些字符?](http:// stackoverflow。問題/ 2431073 /我怎麼做 - 我插入和刪除一些文件中的字符) – Mat 2012-01-27 12:11:10

回答

7

不,沒有辦法將字符插入到現有文件中。你將需要使用第二個文件來做到這一點。

+1

This並不完全正確。你可以再次尋找(),fread(),seek()和fwrite()。當然,因此尾巴必須適合內存。 – ckruse 2012-01-27 12:16:09

+1

@ckruse:那麼,如果'fwrite()'由於某種原因沒有完成,你還有可能破壞原始文件。因此,我不認爲這種方法是一個可行的解決方案。 – NPE 2012-01-27 12:17:04

+0

你說服了我。 – ckruse 2012-01-27 12:18:51

2

沒有,也沒有辦法。您必須創建一個新文件或將該文件的內容向後移動2個字符。

0

您可以將文件加載爲塊(在您的情況下爲80個字符),然後附加兩個字符(換行)並將內容寫入anohter文件。

16

雖然有兩種技術可以在原地進行,但您正在使用文本文件並希望執行插入操作。操作系統通常不支持文本文件插入作爲文件系統原語,他們沒有理由應該這樣做。

最好方式做那種事就是打開你的文件進行讀取,打開一個只寫一個新的文件,複製將插入點之前的文件的一部分,插入數據,複製休息,然後將新文件移到舊文件上。

這是一種常用技術,它有一個目的。如果出現任何問題(例如使用您的系統),您仍然擁有原始文件,並且可以稍後重複交易。如果啓動進程的兩個實例並使用特定模式,則第二個實例能夠檢測到事務已經啓動。通過專有文件訪問,它甚至可以檢測事務是否中斷或仍在運行。

即使您要求他們在原地工作(sed -i),這種方式也不會比直接在原始文件上執行的任何技術更容易出錯,並且被所有傳統工具(如sed)使用。另一個好處是,在覆蓋之前,您始終可以將原始文件重命名爲帶備份後綴的文件(sed也提供此類選項)。

即使您的程序正在編寫一個全新的版本並且不使用原始文件,配置文件也經常使用相同的技術。由於許多互聯網雜誌都聲稱ext4意外地將配置文件截斷爲零長度,這一點並不長。這正是因爲一些應用程序在系統被強制關閉時保持配置文件打開並被截斷。那些應用程序經常在之前篡改原始配置文件,他們已經準備好數據,然後甚至保持打開狀態而不同步它們,這使數據損壞的窗口變得更大。

TL; DR版本:

當你珍惜你的數據,你不具備更換數據準備好之前摧毀它。

1

這是我用這種東西的功能:

int finsert (FILE* file, const char *buffer) { 

    long int insert_pos = ftell(file); 
    if (insert_pos < 0) return insert_pos; 

    // Grow from the bottom 
    int seek_ret = fseek(file, 0, SEEK_END); 
    if (seek_ret) return seek_ret; 
    long int total_left_to_move = ftell(file); 
    if (total_left_to_move < 0) return total_left_to_move; 

    char move_buffer[1024]; 
    long int ammount_to_grow = strlen(buffer); 
    if (ammount_to_grow >= sizeof(move_buffer)) return -1; 

    total_left_to_move -= insert_pos; 

    for(;;) { 
     u16 ammount_to_move = sizeof(move_buffer); 
     if (total_left_to_move < ammount_to_move) ammount_to_move = total_left_to_move; 

     long int read_pos = insert_pos + total_left_to_move - ammount_to_move; 

     seek_ret = fseek(file, read_pos, SEEK_SET); 
     if (seek_ret) return seek_ret; 
     fread(move_buffer, ammount_to_move, 1, file); 
     if (ferror(file)) return ferror(file); 

     seek_ret = fseek(file, read_pos + ammount_to_grow, SEEK_SET); 
     if (seek_ret) return seek_ret; 
     fwrite(move_buffer, ammount_to_move, 1, file); 
     if (ferror(file)) return ferror(file); 

     total_left_to_move -= ammount_to_move; 

     if (!total_left_to_move) break; 

    } 

    seek_ret = fseek(file, insert_pos, SEEK_SET); 
    if (seek_ret) return seek_ret; 
    fwrite(buffer, ammount_to_grow, 1, file); 
    if (ferror(file)) return ferror(file); 

    return 0; 
} 

使用方法如下:

FILE * file= fopen("test.data", "r+"); 
ASSERT(file); 

const char *to_insert = "INSERT"; 

fseek(file, 3, SEEK_SET); 
finsert(file, to_insert); 

ASSERT(ferror(file) == 0); 
fclose(file); 

這(爲他人在這裏所提到的)理論上可損壞,如果一個文件有是一個錯誤,但這裏有一些代碼實際上做到這一點......這樣做就地通常很好,但你應該備份文件,如果你擔心它...