[英]Replace line in text-file using C
我想使用 C 在帶有heet
的文本文件中更改包含#
符號的行。
我已經嘗試過這種方式,但它沒有徹底工作,它只是替換字符並覆蓋而不是整個字符串,就像我想要的那樣。
有沒有其他技巧可以從文件中刪除或刪除整行? 所以,我們可以很容易地更換它。
myfile.txt:(執行前)
Joy
#Smith
Lee
Sara#
Priyanka
#Addy
代碼:
#include <stdio.h>
#include <string.h>
int main() {
FILE *pFile;
fpos_t pos1, pos2;
int line = 0;
char buf[68]
char *p;
char temp[10] = "heet";
pFile = fopen("myfile.txt", "r+");
printf("changes are made in this lines:\t");
while (!feof(pFile)) {
++line;
fgetpos(pFile, &pos1);
if (fgets(buf, 68, pFile) == NULL)
break;
fgetpos(pFile, &pos2);
p = strchr(buf, '#');
if (p != NULL) {
printf("%d, " , line);
fsetpos(pFile, &pos1);
fputs(temp, pFile);
}
fsetpos(pFile, &pos2);
}
fclose(pFile);
return 0;
}
myfile.txt:(執行后)
Joy
heetth
Lee
heet#
Priyanka
heety
輸出:
changes are made in this lines: 2, 4, 6,
myfile.txt:(我想得到)
Joy
heet
Lee
heet
Priyanka
heet
做你想做的最好的方法是使用像 sed 這樣的實用程序。 它比您(或我)編寫的任何內容都更快,占用的內存更少。
除此之外,讓我們假設您想繼續自己編寫它。
文件就像一個長字節數組。 如果您想增加或減少一行的長度,它會影響文件其余部分中每個字節的位置。 結果可能比原始結果更短(或更長)。 由於結果可能更短,就地修改文件是一個壞主意。
以下偽代碼說明了一種簡單的方法:
open original file
open output file
allocate a line buffer that is large enough
read a line from the original file
do
return an error if the buffer is too small
manipulate the line
write the manipulated line to the output file
read a line from the original file
loop until read returns nothing
sed 做得更聰明。 我曾經看到過關於 sed 如何工作的解釋,但我的 google karma 似乎找不到它。
編輯:如何使用 sed 做到這一點:
sed -e 's/.*\#.*/heet/g' myfile.txt
sed
的 s 或替代命令可以用另一個字符串替換一個字符串或正則表達式。
上面的命令解釋為:
用heet
替換其中某處帶有#
任何行。 最后的 g 告訴sed
全局執行此操作,即在整個文件中執行此操作。
Edit2:默認情況下,sed 寫入標准輸出。 要重寫文件,您應該將輸出重定向到一個文件,然后重命名它。 在 linux 中,執行以下操作(您可以使用system
從 C 運行命令行內容):
sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt
rm myfile.txt
mv temp_file123.txt myfile.txt
來自 C:
system("sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt");
system("rm myfile.txt");
system("mv temp_file123.txt myfile.txt");
如果您只想通過一次調用system
,請將所有命令行內容放在一個 shell 腳本中。
您可能應該像對待 UNIX 實用程序一樣對待輸入/輸出,並通過讀取整個輸入並像sed
一樣寫入整個輸出來替換該行。 編輯該行會很痛苦,因為您需要將以下文本“向下”移動以使其工作。
您無法像在代碼中那樣通過覆蓋文件來實現您的目標,因為heet
比#
長 3 個字節,並且沒有標准函數可以在文件中間插入字節。
還要注意這些重要問題:
fopen()
成功打開文件。 如果文件不存在或無法以讀取+更新模式打開,則您有未定義的行為。 while (!feof(pFile))
不會正好停在文件末尾,因為feof()
返回的文件末尾指示符僅在讀取操作失敗時設置,而不是在此之前設置。 你應該寫:
while (fgets(buf, 68, pFile) != NULL) {
如果文件的行超過 66 個字符,則行號將被錯誤計算。
有兩種方法可以替換文件中的文本:
remove()
和臨時文件重命名與為原始名稱rename()
這種方式會占用存儲設備上的額外空間,並且需要您可以創建一個新文件並確定一個與現有文件名不沖突的文件名。這是使用第二種方法的修改版本:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE *pFile;
int c, line, changes;
unsigned char *buf;
size_t pos, length, size;
char replacement[] = "heet";
/* open the file */
pFile = fopen("myfile.txt", "r+");
if (pFile == NULL) {
printf("cannot open myfile.txt\n");
return 1;
}
/* read the file */
buf = NULL;
length = size = 0;
while ((c = getc(pFile)) != EOF) {
if (length == size) {
size = size + size / 2 + 128;
buf = realloc(buf, size);
if (buf == NULL) {
printf("not enough memory to read myfile.txt\n");
fclose(pFile);
return 1;
}
}
buf[length++] = c;
}
/* write the modified contents */
rewind(pFile);
line = 1;
changes = 0;
for (pos = 0; pos < length; pos++) {
c = buf[pos];
if (c == '\n')
line++;
if (c == '#') {
if (changes++ == 0)
printf("changes are made in this lines:\t");
else
printf(", ");
printf("%d", line);
fputs(replacement, pFile);
} else {
putc(c, pFile);
}
}
free(buf);
fclose(pFile);
if (changes == 0)
printf("no changes were made\n");
else
printf("\n");
return 0;
}
要使用fwrite
或任何文件寫入函數重寫文件中的單詞,請使用fgetpos
和fsetpos
。 否則單獨查找文件指針是行不通的。 仍然是這項工作,如果文件指針是文件的結尾,則意味着可以追加。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.