linux c刪除檔案中指定內容行或指定行
阿新 • • 發佈:2019-01-08
用C語言來操作檔案內容還是有點煩的(尤其是刪除內容,或者是修改非等長度的內容),沒有現成的API呼叫,只能自己手動寫;
網上查了下資料基本就兩個方案:
1、增加個臨時檔案;把原始檔內容逐個位元組或者逐行讀取出來,然後修改或者丟棄,放到臨時檔案中,當把原始檔中所有內容過濾後,再把臨時檔案全部覆蓋回原始檔;
2、讀取到記憶體中修改;把整個檔案讀取到記憶體中,然後修改,再覆蓋回到原始檔;
第1種方案,會多一個臨時檔案,這樣不太安全,使用C語言來做這種事,很大一方面就是考慮到安全性;
第2種方案,讀取到記憶體中,這種方法有個缺陷是你不知道原始檔大小,如果原始檔很大的話,你要分配很大記憶體;
我們應該懷疑下,為什麼 shell 命令可以很方便的刪除、修改檔案內容,這絕對不會有臨時檔案產生,也不會佔用多大記憶體,或者可以說佔用的記憶體不會隨著檔案的大小而改變?
我想了下,有個新方案,或許就是shell命令的原理;(我沒有去研究shell命令的刪除實現);
新方案是利用檔案指標,如下圖:
其實看下上面的圖就應該知道了,就是利用檔案指標,類似佇列那樣,一個是入佇列一個是出佇列;
流程:
a、首先儲存兩個位置,1、讀取檔案內容的偏移量;2、寫入檔案內容的偏移量;
b、用 seek + 讀檔案偏移量 來設定下讀取內容指標偏移量,讀取一行資料; 同時修改下讀取偏移量;
c、對這一行資料進行判斷,修改,或者刪除;
d、用seek + 寫入偏移量 來設定下檔案位置指標,把 c 步驟中修改的內容回寫到檔案;同時修改下寫入偏移量;
e、迴圈讀取所有原始檔內容;
f、根據寫入檔案偏移量(因為寫入的才是有效的資料,寫入偏移量就代表了檔案大小),擷取下檔案,把無效內容幹掉;
下面是程式碼實現:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #define BUFF_LEN 256 /* * 刪除檔案中無效內容 * */ int clean_invalue_info(FILE *file_fd) { assert(file_fd); char buff[BUFF_LEN] = {0}; int buff_len = 0; long offset_read = 0; long offset_write = 0; while(fgets(buff, BUFF_LEN, file_fd)) { buff_len = strlen(buff); if (strstr(buff, "yzh")) { //有效資料要考慮移動 if (offset_read == offset_write) { offset_write = offset_write + buff_len; offset_read = offset_read + buff_len; continue; } else { /*移動資料*/ fseek(file_fd, offset_write, SEEK_SET); fputs(buff, file_fd); offset_write = offset_write + buff_len; offset_read = offset_read + buff_len; fseek(file_fd, offset_read, SEEK_SET); continue; } } offset_read = offset_read + buff_len; } ftruncate(fileno(file_fd),offset_write); } int testt(FILE *file_fd) { char buff[BUFF_LEN] = {0}; int buff_len = 0; long offset_read = 0; char *str = "11111111111"; fseek(file_fd, 0, SEEK_SET); fputs(str, file_fd); fgets(buff, BUFF_LEN, file_fd); printf("1. %s\n", buff); buff_len = strlen(buff); fgets(buff, BUFF_LEN, file_fd); printf("2. %s\n", buff); fseek(file_fd, buff_len, SEEK_SET); fgets(buff, BUFF_LEN, file_fd); printf("3. %s\n", buff); return 0; } int main(int argc, char *argv[]) { FILE *file_fd = fopen("./tt", "r+"); clean_invalue_info(file_fd); // testt(file_fd); fclose(file_fd); return 0; }
上面程式碼已經除錯通過,為方便理解,沒有優化過;