3

I had never realized this.I could have very well assumed subconsciously as a hard fact that I can transition between reading and writing on an existing file opened it update mode,just like that.But two questions on SO(1,2) drove me skeptical and I decided to try it out.Here's what I find:

In the first program,prog1,I work on a file source.txt which only has the line Lethal weapon.I read the first world Lethal using fscanf() and intend to write " musket" right after that expecting to get Lethal musket.But it simply fails, and I still get the original content Lethal weapon at the end of the write operation.But in that first program,if I insert the line fseek(fp,0,SEEK_CUR), the write operation works fine and I get Lethal musket.I notice that fseek(fp,0,SEEK_CUR) serves no purpose other than call fseek() just for the sake of it,as there is no net seeking at all.

But in the second program,prog2,the same scenario doesn't need thatfseek(fp,0,SEEK_CUR) statement.To be exact,in the second program,in contrast to reading to middle of file as in first program, here I read to the end of file,and then start writing there.Here the write is successful even without using fseek(fp,0,SEEK_CUR) and I get the desired content Lethal weapon sale.

Question: Why can't we transition from read to write mode in the middle of the file and what difference fseek(fp,0,SEEK_CUR) makes to get it working?And at the same time, why the same transition works without any fuss if we read to end of file and write there?Why fseek(fp,0,SEEK_CUR) is not needed in second case?How advisable is my use of fseek(fp,0,SEEK_CUR) to make the write successful in the first program?Any better alternative?

Two questions on SO seem to have addressed the same issue to some extent,but since they were based more on seeking explanation of excerpts from texts/books,the answers oriented towards them doesn't seem to address what I intend to know in precise terms.

//PROG1

#include <stdio.h>

int main ()
{
    FILE *fp=fopen("D:\\source.txt","r+");
    char arr[20],brr[50];
    fscanf(fp,"%s",arr);
    printf("String is %s\n",arr);
    //fseek(fp,0,SEEK_CUR);  //Doesn't work without it
    fprintf(fp," musket");
    rewind(fp);
    fgets(brr,50,fp);
    printf("New string is %s",brr);
    fclose(fp);
}

Output:

1) Without fseek() -- Lethal weapon

2) With fseek() -- Lethal musket

//PROG2    

#include <stdio.h>

int main ()
{
    FILE *fp=fopen("D:\\source.txt","r+");
    char arr[20],brr[50];
    fgets(arr,20,fp);
    printf("Initial line is %s\n",arr);
    fprintf(fp," sale"); //writes to end of file
    rewind(fp);
    printf("New string is %s",fgets(brr,50,fp));
    fclose(fp);
}

Output without fseek(): -- Lethal weapon sale

Community
  • 1
  • 1
Rüppell's Vulture
  • 3,583
  • 7
  • 35
  • 49
  • mode 'b' is binary mode, usually use `fread` for reading, and `fwrite` for writing`.And I try your code but behavior is different – MYMNeo May 24 '13 at 05:59
  • @MYMNeo Since I am not using numbers,binary mode is not an issue here.Still I agree it's better to use text mode to illustrate my point.Editing it.Thanks for pointing out.BTW,what is the behavior in your computer? – Rüppell's Vulture May 24 '13 at 06:03
  • @MYMNeo And I must point out that `fread` is not very helpful while reading strings from files as you have to append the Null character yourself,unlike `fscanf()` – Rüppell's Vulture May 24 '13 at 06:05
  • PROG1, no `fseek` is also Lethal musket – MYMNeo May 24 '13 at 06:06
  • @MYMNeo I double checked it.It's still **lethal weapon** without `fseek()` on my computer and it seems to agree with what the other two questions and their links say. – Rüppell's Vulture May 24 '13 at 06:09
  • I find lines in "Advanced Programming in the UNIX Environment".It says when reading and writing same file with type "+", if no `fflush`,`fseek`,`fsetpos` or `rewind`, can not write content following the output.(My mother tongue is not English, this is my translation not origin). – MYMNeo May 24 '13 at 06:32
  • @MYMNeo Seems we both are lost MYMNeo.Let's wait and watch what the brighter guys have to answer.Let's hope I get answers before I put a bounty on it. – Rüppell's Vulture May 24 '13 at 06:35
  • For why the second doesn't need fseek(), I think the key is the last bit of what you quoted below: "_reading operation which did not reach the end-of-file followed by a writing operation_". In the 2nd case, the read DID reach the end of file, so doesn't need a flush/fseek. For the variance in the first example, it will be down to implementations: some compiler/platform/OS will **need** the fseek/flush but on some it _might_ work without (but, since it's not defined to work, you should still include it). – TripeHound Mar 19 '14 at 13:02
  • I've always visualized this situation as having a READ pointer and a WRITE pointer. You read the first word, but the WRITE pointer is still 'undefined' (in a sense). The fseek sets the READ & WRITE pointers, allowing the write to work as expected. Perhaps a bit weird imaginings, but it has worked for me for many years. Also, if you read the entire file (as in prog2, the WRITE pointer gets updated), then you can write normally. Again, it's almost 'magic', but it works for me. Two pointers, but they don't track each other automatically. – lornix Jun 04 '14 at 09:51

1 Answers1

0

Actually, it looks like a bug in your libc implementation. File I/O streams are usually a libc abstraction over the file descriptor based binary I/O implemented by the OS kernel. So any strange behaviour shall be attributed to your specific libc quirks.

Since you're apparently using Windows, that may be the source of your problems. What is the compiler you're using? There is no such problem with GCC 4.6.1 and glibc-2.13 on Ubuntu 11.10.

Alexander Amelkin
  • 759
  • 1
  • 9
  • 15
  • I use CodeBlocks/gcc on windows. – Rüppell's Vulture May 24 '13 at 11:58
  • And to quote from `cplusplusreference` `"For files open for update (those which include a "+" sign), on which both input and output operations are allowed, the stream should be flushed (fflush) or repositioned (fseek, fsetpos, rewind) between either a writing operation followed by a reading operation or a reading operation which did not reach the end-of-file followed by a writing operation."` – Rüppell's Vulture May 24 '13 at 11:58