I have been trying out some file io and have written the following:
#include <stdio.h>
int main(){
char stuff [80];
FILE *file;
file=fopen("hello.cheese", "w+");
fprintf(file, "%s", "cheese");
fscanf(file, "%s", stuff);
printf("%s", stuff);
fprintf(file, "\n%s", stuff);
fclose(file);
return 0;
}
All this does is put ^A in the file (next line underneath cheese) and print nothing.
You might want to read closely fopen description, especially
When a file is opened with update mode ( '+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, the application shall ensure that output is not directly followed by input without an intervening call to fflush() or to a file positioning function ( fseek(), fsetpos(), or rewind()), and input is not directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
You used 'w+' mode, which allows reading and writing, but did not flush, nor rewind file pointer after write.
As a side note, Your code could use some error checking (NULL != file).
Related
I have following problem:
void edit(FILE *f, int cnt)
{
int i = 0;
int offset = 0;
rewind(f);
schedule todo;
schedule *p = &todo;
fprintf(stdout, "\n%s\n", "------------------------------------------------");
fread(&todo, sizeof(schedule), 1, f);
while (!feof(f)) {
fprintf(stdout, "%6d%18s\n",
++i, todo.title);
fread(&todo, sizeof(schedule), 1, f);
}
fprintf(stdout, "%s\n\n", "-------------------------------------------------");
fprintf(stdout, "%s\n\n", "Number: ");
scanf("%d", &i);
getchar();
rewind(f);
offset = (long) sizeof(schedule);
fseek(f, (i - 1)*offset, SEEK_CUR);
fread(&todo, sizeof(schedule), 1, f);
printf("Edit: %s\n", todo.title);
fprintf(stdout, "%6d%18s%8s%10s%8d\n",
todo.number, todo.title, todo.where, todo.details, todo.importance);
scanf("%s", todo.title);
fwrite(&todo, (long)sizeof(todo.title), 1, f);
}
It's part of editing data codes.
This is what I expected.
If a user put a number(i in the code), the program will find the location (in binary file).
Then, the user put todo.title by (scanf("%s", todo.title);) and the program will edit it by using
fwrite(&todo, (long)sizeof(todo.title), 1, f);
I got a warning like
Expression: ("Flush between consecutive read and write.", !stream.has_any_of(_IOREAD))
I think there's problems with buffer, but I can't fix this.
If you have a file open for update (read and write) then the C11 standard requires:
§7.21.5.3 The fopen function
¶7 When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.
The quote comes from the C11 specification, but the wording is essentially unchanged in all versions of the standard.
Note that you must do a seek operation, even if it is just fseek(f, 0, SEEK_CUR), between a read and a write operation, and between a write and a read operation.
Your code has an fread() followed by an fwrite() with no intervening fseek(). That's probably an oversight since you change the record and overwrite the next record in the file with the updated information. You probably need an fseek(f, -(long)sizeof(schedule), SEEK_CUR) or thereabouts to move back and overwrite the record just read and changed.
I have the following simple code:
#include <stdio.h>
int main(){
char buffer[20] = "abc";
FILE *pFile;
pFile = fopen("myfile1.txt", "r+");
fputs("def", pFile);
fgets(buffer, 20, pFile);
printf("buffer content: %s\n", buffer);
fclose(pFile);
return 0;
}
the output is: buffer content: abc, not def as it has just been written to the file. Could someone please explain?
If you want to read randomly, you first have to tell the file reading routines, where you want to start.
Use fseekto do this.
e.g.: fseek(pFile, 0, SEEK_SET) before you try to get something with fgets.
From cppreference:
In update mode ('+'), both input and output may be performed, but output cannot be followed by input without an intervening call to fflush, fseek, fsetpos or rewind, and input cannot be followed by output without an intervening call to fseek, fsetpos or rewind, unless the input operation encountered end of file.
You're not doing any of those things between writing and reading.
In the code below, extra spcaes (may be around 300 space) are getting appended if I write data after seeking the file pointer to the start position after the line
fseek(fp1,0,SEEK_SET);
If I comment second fputs() function call, there is no issue.
Also the inputted data is not getting appended at the end, instead only spaces are getting appended.
I am unable to identify the problem.
I am using TDM-GCC-64 compiler.
For testing purpose, file1.txt had contents "Welcome to You All" at the beginning.
Inputted data: "Today"
Output after execution of the program: "Todayme to You All" followed by many spaces.
int main()
{
FILE *fp1;
char ch;
char data[50];
fp1=fopen("file1.txt", "r+");
if(fp1==NULL)
{
printf("Error in Opening the file\n");
return(0);
}
printf("Read and Write Mode. The data in the file is\n");
while((ch=getc(fp1))!=EOF)
{
putc(ch,stdout);
}
// Write some data at the end of the file
printf("\nEnter some data to be written to the file\n");
gets(data);
fseek(fp1,0,SEEK_END);
fputs(data,fp1);
fseek(fp1,0,SEEK_SET);
fputs(data,fp1);
printf("data in file after write operation is\n");
while((ch=getc(fp1))!=EOF)
{
putc(ch,stdout);
}
fclose(fp1);
return 0;
}
You should check the fine print in the fopen documentation:
In update mode ('+'), both input and output may be performed, but output cannot be followed by input without an intervening call to fflush, fseek, fsetpos or rewind, and input cannot be followed by output without an intervening call to fseek, fsetpos or rewind, unless the input operation encountered end of file.
Reading and writing might be buffered, but still share a single file position. Switching modes without alerting the runtime (fseek) could mess up the buffering. Like you have noticed!
Could someone tell me why the file doesn't change? It works when I use rewind or fseek but not otherwise.
What's the standard way of using fputs after fgets. The file indicator is at position 9 so fputs must write after that, but it doesn't do anything.
In file:
abcd efgh ijkl mnor
In source code:
char c;
char str[15];
FILE *fp = fopen("d:\\data.txt","r+");
fgets(str, 10, fp);
// fseek(fp, 9, SEEK_SET);
// rewind(fp);
printf("%d\n", ftell(fp));
// ftel shows that it's in "9".
printf("%s", str);
fputs(str, fp);
// why its not working
fclose(fp);
Regarding the definition of fopen/'+' in the C standard (e.g. as in this online C standard draft), switching from reading to writing requires an intermediate call to a file positioning function (emphasis are mine):
7.21.5.3 The fopen function
(7) When a file is opened with update mode ('+' as the second or third
character in the above list of mode argument values), both input and
output may be performed on the associated stream. However, output
shall not be directly followed by input without an intervening call to
the fflush function or to a file positioning function (fseek, fsetpos,
or rewind), and input shall not be directly followed by output without
an intervening call to a file positioning function, unless the input
operation encounters end- of-file. Opening (or creating) a text file
with update mode may instead open (or create) a binary stream in some
implementations.
So I'd suggest you write the following code to overcome your problem:
fseek ( fp , 0, SEEK_CUR);
fputs(str, fp);
The MS documentation for fopen says this:
When the "r+", "w+", or "a+" access type is specified, both
reading and writing are enabled (the file is said to be open for
"update"). However, when you switch from reading to writing, the input
operation must encounter an EOF marker. If there is no EOF, you
must use an intervening call to a file positioning function. The file
positioning functions are fsetpos, fseek, and rewind. When you
switch from writing to reading, you must use an intervening call to
either fflush or to a file positioning function.
I was toying around with some code which was opening, reading, and modifying a text file. A quick (simplified) example would be:
#include <stdio.h>
int main()
{
FILE * fp = fopen("test.txt", "r+");
char line[100] = {'\0'};
int count = 0;
int ret_code = 0;
while(!feof(fp)){
fgets(line, 100, fp);
// do some processing on line...
count++;
if(count == 4) {
ret_code = fprintf(fp, "replaced this line\n");
printf("ret code was %d\n", ret_code);
perror("Error was: ");
}
}
fclose(fp);
return 0;
}
Now on Linux, compiled with gcc (4.6.2) this code runs, and modifies the file's 5th line. The same code, running on Windows7 compiled with Visual C++2010 runs and claims to have succeeded (reports a return code of 19 characters and perror says "No error") but fails to replace the line.
On Linux my file has full permissions:
-rw-rw-rw- 1 mike users 191 Feb 14 10:11 test.txt
And as far as I can tell it's the same on Windows:
test.txt (right click) -> properties -> Security
"Allow" is checked for Read & Write for user, System, and Admin.
I get the same results using MinGW's gcc on Windows so I know it's not a Visual C++ "feature".
Am I missing something obvious, or is the fact that I get no errors, but also no output just an undocumented "feature" of using r+ with fopen() on Windows?
EDIT: Seems even at Microsoft's site they say "r+" should open for reading and writting. They also made this note:
When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired.
So I tried:
...
if(count == 4) {
fflush(fp);
ret_code = fprintf(fp, "replaced this line\n");
fflush(fp);
printf("ret code was %d\n", ret_code);
...
to no avail.
According to the Linux man page for fopen():
Reads and writes may be intermixed on read/write streams in any order.
Note that ANSI C requires that a file positioning function intervene
between output and input, unless an input operation encounters
end-of-file. (If this condition is not met, then a read is allowed to
return the result of writes other than the most recent.) Therefore it
is good practice (and indeed sometimes necessary under Linux) to put
an fseek(3) or fgetpos(3) operation between write and read operations
on such a stream. This operation may be an apparent no-op (as in
fseek(..., 0L, SEEK_CUR) called for its synchronizing side effect.
So, you should always call fseek() (as, eg. fseek(..., 0, SEEK_CUR)) when switching between reading and writing from a file.
Before performing output after input, an fflush() isn't any good - you need to perform a seek operation. Something like:
fseek(fp, ftell(fp), SEEK_SET); // not fflush(fp);
from the C99 standard (7.19.5.3/6 "The fopen functoin):
When a file is opened with update mode ('+' as the second or third
character in the above list of mode argument values), both input and
output may be performed on the associated stream. However, output
shall not be directly followed by input without an intervening call to
the fflush function or to a file positioning function (fseek,
fsetpos, or rewind), and input shall not be directly followed by output
without an intervening call to a file positioning function, unless the
input operation encounters end-of-file.