簡體   English   中英

如何在C中編輯txt文件的特定行

[英]How to edit a specific line of a txt file in C

我目前正在嘗試在C中編輯.txt文件的特定行。im正在使用的文件如下所示:

像素位置和RGB顏色

現在說我要更改在圖像上突出顯示的特定行上寫的內容:

400,300:(255,255,255)#FFFFFF

到這個:

400,300:(000,000,000)#000000

基本上,我試圖在特定像素上創建黑點,在本例中為400,300。 這是我的代碼:

#include <stdio.h>
int main(void)
{
    const char *filename = "sample.txt";
    int x = 400;
    int y = 300;

    FILE *fp;
    fp = fopen(filename, "w+");

    // Algorithm that reads all the file

    // If("Operation that reads" == x+","+y)
    // {
    //     Replace the line information after where it starts with "400,300"
    //     Like this : 400,300: (000,000,000) #000000
    // }


    // Algorithm that saves the file with the changes.


    fclose(fp)
    printf("Ok - File %s saved\n", filename);
    return 0;

創建,打開和編輯.txt文件對我來說是一種新事物,所以我不知道該怎么做,我越了解它,就會越困惑。 我該如何解決這個問題?什么代碼適合這里?

更新1:

FILE *fp;
fp = fopen(filename, "w+");

if ( fp == NULL )
{
    printf("Error while opening file"); 
}   

好吧,在閱讀完您下面的內容后,我想到了一個主意,但仍然需要工作。 我將打印從文件到char數組的所有內容。 之后,我將在每個插槽中搜索我正在尋找的特定代碼行,並保留數字插槽。 在那之后,我將轉到數組,運行它,並且當涉及到該特定插槽時,我將替換所需的數據。 現在,我需要做的就是將文件中的信息替換為數組中的信息,保存文件並解決問題。 但是我在代碼中遇到了錯誤,並且錯過了一些會清除txt文件並保存新數據的代碼位。

更新2:

#include <stdio.h>

int main(void)
{

int x,y;
int k = 0;
int noline; // Used to locate which line is the string im looking for
char search; // Used to compare with each string
char blackcode = (char)000; // In RGB, Black uses (000,000,000)
char blackhexcode = (char)000000; // The hexcode for black is #000000
const char *filename = "sample.txt";
char* strings[480000]; // Since its a 800x600 resolution picture, it needs that many lines.
char line[30]; // Space created to store whats inside each line of the file before transfering
char temp;

FILE * fp;
fp= fopen(filename, "r+");

if ( fp == NULL )
{
    printf("Error while opening file"); 
}   
else
{
    while(fgets(line, sizeof line, fp))
    {       
        strings[k]=strdup(line); // ERROR HERE! What Am I missing?
        k++;
    }

    for(k = 0; k< sizeof strings; k++)
    {
        temp = scanf("%[^:]s", strings[k]);
        search = ("%s,%s",x,y);

        if(temp = search)
        {
            noline = k;
        }
        else
        {
            printf("Error : Wrong Coordinates");
        }
    }

    for(k = 0; k < sizeof strings; k++)
    {
        if(k == noline)
        {
            strings[k] = ("%d,%d: (%s,%s,%s) #%s", x, y, blackcode, blackcode, blackcode, blackhexcode); // ERROR HERE! What did i did wrong?
        }
    }

    // Code that cleans the txt file and saves the array back to txt file
}
fclose(fp);

}

您缺少的內容在概念上與fopen有關。 當考慮使用fopen打開文件時,需要特別注意文件模式的效果。 如果您仔細查看有關"w""w+"手冊頁 在這兩種情況下,現有文件都會被截斷 "w"的情況下為0-length

為避免此問題,一種方法是將整個文件讀入緩沖區,然后對緩沖區進行更改,將修改后的緩沖區寫回到原始文件名。 這樣可以避免嘗試嘗試插入/刪除字節而不重寫文件的其余部分的可能性。

要處理將文件讀入緩沖區的操作,發布的鏈接會覆蓋文本文件中的特定行嗎? ,提供了更改文件中單行的路線圖。 您的情況有所不同。 您要查找/替換所有出現的特定模式。 (這是截斷問題帶來的挑戰)。但是,那里的許多解決方案都可以應用於將文件本身讀取到緩沖區中。 特別是使用fseekftell

使用fseekftell提供了一種簡單的方法來確定文件的大小(或長度),然后可以將其用於分配空間以將整個文件保存在內存中。 以下是一種簡單函數的方法,該函數采用字符指針和文件指針的地址,然后使用fseekftell分配所需的內存來保存文件,然后通過以下單個操作將文件讀入緩沖區( filebuf ): fread 緩沖區被填充到位並返回。 指向文件長度fplen指針將傳遞給該函數,以便在調用函數中返回該長度main()在這種情況下為main() )。 如果成功,則返回指向緩沖區的指針(否則返回NULL )將允許返回的賦值,以及一種確定讀取成功/失敗的方法:

char *read_file_into_buf (char **filebuf, long *fplen, FILE *fp)
{
    fseek (fp, 0, SEEK_END);
    if ((*fplen = ftell (fp)) == -1) {  /* get file length */
        fprintf (stderr, "error: unable to determine file length.\n");
        return NULL;
    }
    fseek (fp, 0, SEEK_SET);  /* allocate memory for file */
    if (!(*filebuf = calloc (*fplen, sizeof *filebuf))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return NULL;
    }

    /* read entire file into filebuf */
    if (!fread (*filebuf, sizeof *filebuf, *fplen, fp)) {
        fprintf (stderr, "error: file read failed.\n");
        return NULL;
    }

    return *filebuf;
}

將文件存儲在內存中后,難題的第二步就是掃描緩沖區並進行所需的替換。 您可以應用許多不同的調整來優化搜索/替換,但以下只是簡單的基本搜索/替換,其中唯一的優化嘗試是在使用普通string.h字符串之前比較起始字符。比較功能以檢查您指定的搜索字符串。 該函數返回已進行的替換次數,因此您可以確定是否需要寫出原始文件名:

unsigned find_replace_text (char *find, char *rep, char *buf, long sz)
{
    long i;
    unsigned rpc = 0;
    size_t j, flen, rlen;

    flen = strlen (find);
    rlen = strlen (rep);

    for (i = 0; i < sz; i++) {
        /* if char doesn't match first in find, continue */
        if (buf[i] != *find) continue;

        /* if find found, replace with rep */
        if (strncmp (&buf[i], find, flen) == 0) {
            for (j = 0; buf[i + j] && j < rlen; j++)
                buf[i + j] = rep[j];
            if (buf[i + j])
            rpc++;
        }
    }

    return rpc;
}

可以使用示例數據將所有內容組合到一個簡短的示例程序中,如下所示。 程序期望文件名作為第一個參數(如果沒有給出文件名,則默認情況下將從stdin讀取並寫入stdout )。 您還可以始終包含其他驗證檢查:

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

char *read_file_into_buf (char **filebuf, long *fplen, FILE *fp);
unsigned find_replace_text (char *find, char *rep, char *buf, long sz);

int main (int argc, char **argv) {

    char *srchstr = "400,300";
    char *repstr = "400,300: (000,000,000) #000000";
    char *filebuf = NULL;
    long int fplen = 0;
    FILE *fp = NULL;

    /* open file for reading (default stdin) */
    fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open */
        fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
        return 1;
    }

    if (!read_file_into_buf (&filebuf, &fplen, fp)) return 1;
    if (fplen < 1 || fplen >= INT_MAX) { /* validate file length */
        fprintf (stderr, "error: length of file invalid for fwrite use.\n");
        return 1;
    }
    if (fp != stdin) fclose (fp);

    /* find/replace text in filebuf */
    if (!find_replace_text (srchstr, repstr, filebuf, fplen)) {
        printf ("no replacements made.\n");
        return 0;
    }

    /* open file for writing (default stdout) */
    fp = argc > 1 ? fopen (argv[1], "w") : stdout;

    if (!fp) {  /* validate file open */
        fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
        return 1;
    }

    /* write modified filebuf back to filename */
    if (fwrite (filebuf, sizeof *filebuf, (size_t)fplen, fp) != (size_t)fplen) {
        fprintf (stderr, "error: file write failed.\n");
        return 1;
    }
    if (fp != stdout) 
        if (fclose (fp) == EOF) {
            fprintf (stderr, "error: fclose() returned EOF\n");
            return 1;
        }

    free (filebuf);

    return 0;
}

只需在文件底部添加功能即可。 然后,您可以:

編譯

gcc -Wall -Wextra -O3 -o bin/fread_file fread_file.c

(或在編譯器中使用等效的編譯字符串)

輸入文件

$ cat dat/rbgtst.txt
400,280: (234,163,097) #EAA361
400,300: (255,255,255) #FFFFFF
400,320: (064,101,160) #4065A0
400,340: (220,194,110) #DCC26E

更換后使用/歸檔

$ ./bin/fread_file dat/rbgtst.txt
$ cat dat/rbgtst.txt
400,280: (234,163,097) #EAA361
400,300: (000,000,000) #000000
400,320: (064,101,160) #4065A0
400,340: (220,194,110) #DCC26E

或從stdin讀入stdin stdout

$ ./bin/fread_file <dat/rbgtst.txt
400,280: (234,163,097) #EAA361
400,300: (000,000,000) #000000
400,320: (064,101,160) #4065A0
400,340: (220,194,110) #DCC26E

內存/錯誤檢查

在任何動態分配內存的代碼中,您對分配的任何內存塊都有2種責任:(1)始終保留指向該內存塊起始地址的指針,因此,(2)在沒有內存塊的情況下可以將其釋放需要更長的時間。

必須使用一個內存錯誤檢查程序來確保您沒有在所分配的內存塊之外/之外進行寫操作,試圖讀取或基於一個無意化的值進行跳轉,最后確認您已釋放了所有內存已分配。

對於Linux, valgrind是通常的選擇。 有許多微妙的方法來濫用新的內存塊。 使用一個內存錯誤檢查器允許您識別任何問題並確認正確使用的內存你分配,而不是找出問題通過存在segfault 每個平台都有類似的內存檢查器。 它們都很容易使用,只需通過它運行程序即可。 例如:

$ valgrind ./bin/fread_file dat/rbgtst.txt
==13768== Memcheck, a memory error detector
==13768== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==13768== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==13768== Command: ./bin/fread_file dat/rbgtst.txt
==13768==
==13768==
==13768== HEAP SUMMARY:
==13768==     in use at exit: 0 bytes in 0 blocks
==13768==   total heap usage: 3 allocs, 3 frees, 2,128 bytes allocated
==13768==
==13768== All heap blocks were freed -- no leaks are possible
==13768==
==13768== For counts of detected and suppressed errors, rerun with: -v
==13768== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

要確認All heap blocks were freed -- no leaks are possibleERROR SUMMARY: 0 errors from 0 contexts (忽略抑制注意到它只是涉及到缺少調試符號文件不是我的系統上安裝)

查看代碼並了解其功能。 這不是作為您嘗試做的唯一方法,而是作為解決問題的方法的一個示例,同時避免了嘗試一次更改一條線路所固有的陷阱在現有文件中利用偏移量和對該文件的多次讀/寫操作。 如果您有任何問題,請告訴我。

通常,您不能編寫txt文件的特定行。

實際上,txt文件只是一個字節序列。 每行僅由特殊符號“ \\ n”(或符號“ \\ r”,“ \\ n”:有兩種方法)彼此分隔。

因此,如果您重寫某些行,則必須移動剛在新行之后保留在文件中的數據(行)。

但是,如果新行的長度與以前相同,則可以不用擔心而在舊行上書寫。

對於這種情況,我能想到的最好方法是以只讀模式打開文件,然后通過以“ w +”模式打開新文件將所有內容復制到新文件夾。 然后,在讀取的文件中逐行查找,直到找到要更改的行,然后在新的副本文件中自己重寫該行。 然后在讀取的文件中跳過該行,然后繼續。 復制完所需的文件后,可以將其名稱替換為所需的原始文件名。 然后,就好像您按需要編輯文件一樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM