Search code examples
cfiletext-filesfile-copying

Editing a line in a text file using temp file C


I am trying to edit a line in a textfile but i have an unexpected behavior while i am editing the file. What i want to do is adjust a specific line (points : 100) of a text that looks like. In the function i pass arguments by value the new coins to be adjusted and the offset of the file with ftell->user_point. What i get as an output is weird. I try to copy the rest of the file to a temp,with an edited line, and then copy it back to the original file from the point that i copied to temp.(thats the user_point offset with ftell). Here is the original fie with entries like that:

...    
_______________________________________
    nickname     : geo
    password     : cuvctq
    Name         : george
    Surname      : papas
    points       : 100
    participated : 
    past draws   : 0
    Chosen No.   : 
    future draws : 0
    Registered   : Sun Feb 05 19:23:50 2012
...

What i get after 2nd edit run is:

...
    _______________________________________
    nickname     : geo
    password     : cuvctq
    Name         : george
    Surname      : papaspoints       : 98
    participated : 
    past draws   : 0
    Chosen No.   : 
    future draws : 0
    Registered   : Sun Feb 05 19:23:50 2012
...
At the end of the text i get one extra \n after i edit the 
file whch is something i dont want :/

and so further edit will spoil the text... I also get an EXTRA \n at the end of the line which, at least what i think so, is due to "r+" mode which is something that i also dont want...

void coins_adjust(int coins_new,int user_point)
{
    int lines,i,ln_point_copy;
    char buffer[50],buff_copied[50];
    FILE *lottary,*temp;

    memset(buff_copied,'\0',sizeof(char)*50);
    lottary=fopen("customers.txt","r");
    temp=fopen("temp.txt","w");
    fseek(lottary,user_point,SEEK_SET);
    for (lines=0;lines<5;lines++)
    {
        memset(buffer,'\0',sizeof(char)*50);
        if (lines==5)
            ln_point_copy=ftell(lottary);       //from TEMP to CUSTOMERS
        fgets (buffer ,50 , lottary);
    }
    coins_new+=atoi(buffer+15);

    strncpy(buff_copied,buffer,15);     //copy 15 chars and fill with null
    memset(buffer,'\0',sizeof(char)*50);
    itoa (coins_new,buffer,10);          //fix the new line to be entered
    strcat(buff_copied,buffer);          //the edited line is as it is supposed
    strcat(buff_copied,"\n");            //to be with \n at the end.
    puts(buff_copied);

    printf("%s",buff_copied);fflush(stdout);
    fprintf(temp,"%s",buff_copied);
    for(i=getc(lottary); i!=EOF; i=getc(lottary))  //copy to temp
    {
        putc(i, temp);
    }
    fclose(lottary);
    fclose(temp);

    temp=fopen("temp.txt","r");
    lottary=fopen("customers.txt","r+");
    fseek(lottary,ln_point_copy,SEEK_SET);
    for(i=getc(temp); i!=EOF; i=getc(temp))     //copy until eof
    {
        putc(i, lottary);
    }
    fclose(lottary);fclose(temp);

}

I have debugged the program and everything seems to work at least on what values are passed to the arrays where i store the line chars but i cant see why it ignores the \n of the previous line when i try to copy it back to the original... There seems to be a \r char that i cant get rid of while i copy back to the original... Thanks in advance.


Solution

  • I was more thinking about something like this:

    void change_points(int new_points)
    {
        FILE *input  = fopen("customers.txt", "r");
        FILE *output = fopen("temp.txt", "w");
    
        char buffer[256];
    
        while (fgets(buffer, sizeof(buffer), input))
        {
            /* Look for the correct line */
            /* Can also use e.g. "if (strncmp(buffer, "points", 6) == 0)"
             * if it's at the start of the line
             */
            if (strstr(buffer, "points") != NULL)
            {
                int old_points;
    
                sscanf(buffer, "%*s : %d ", &old_points);
    
                /* Format how you like it */
                fprintf(output, "%-13s: %d\n", "points", new_points + old_points);
            }
            else
                fputs(buffer, output);
        }
    
        fclose(output);
        fclose(input);
    
        /* The file "temp.txt" now contains the modifeed text */
        /* Copy either using "fgets"/"fputs", or using "fread"/"fwrite" */
    
        input  = fopen("temp.txt", "r");
        output = fopen("customers.txt", "w");
    
        while (fgets(buffer, sizeof(buffer), input))
            fputs(buffer, output);
    
        fclose(output);
        fclose(input);
    }
    

    It's shorter, simpler, maybe more effective (looping over line-by-line instead of char-by-char), and the line you are looking for can be anywhere in the file without you knowing its exact position.