1. 程式人生 > >linux c刪除檔案中指定內容行或指定行

linux c刪除檔案中指定內容行或指定行

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

上面程式碼已經除錯通過,為方便理解,沒有優化過;