I am facing this strange problem, answer to which is clear to me but I am looking for alternative here. Whenever I open a file in "a+" mode, I am able to read using fread(), if I read it first and then write in it using fprintf(). If I instead write into file first and then read it, I get blank value in output.
I do not want to fclose() the FILE pointer fp after every write because I am doing operations like write->read->write->read.......n iterations.
Is there an optimal way to achieve this ?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <poll.h>
#include <linux/input.h>
int main(){
FILE * fp;
fp = fopen("myback.txt", "a+");
char buf[10];
fprintf(fp, "checking");
fread (buf,1,4,fp);
buf[4] = '\0'; //buf has read n bytes
printf("%s \n", buf);
return 0;
}
From this fopen reference:
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. In update mode, implementations are permitted to use binary mode even when text mode is specified.
So you can't read or write directly after each other, you must explicitly set or reset the file position between each input and output function.
Related
I am trying to write 2 programs that will talk to each other using fifo pipe.
I used the example here (section 5.2), but I changed the mknod there to mkfifo and tried to change gets to fgets.
This is the code (of one program which writes into the fifo):
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h> /*mkfifo, open */
#include <sys/wait.h>
#include <sys/stat.h> /* mkfifo, open */
#include <fcntl.h> /*open */
#define FIFO_PATH "/home/hana/Desktop"
#define BUFFER_SIZE 300
int main()
{
char buffer[BUFFER_SIZE];
int fd;
int wStatus;
mkfifo(FIFO_PATH, 666);
printf("waiting for readers\n");
fd = open(FIFO_PATH, O_RDWR);
while (fgets(buffer, BUFFER_SIZE, fd), !feof(stdin))
{
if ((wStatus = write(fd, buffer, strlen(buffer))) == -1)
perror("write");
else
printf("speak: wrote %d bytes\n", wStatus);
}
return 0;
}
I get a compilation error: passing argument 3 of fgets makes pointer from integer.
So fgets is expecting FILE* and not file descriptor.
What should I do? change something so that fgets works? use another function?
I am compiling with gcc (ansi, pedantic).
Thanks
The answer from whjm is the cause of your error diagnostic, but I think you probably meant
fgets(buffer, BUFFER_SIZE, stdin)
// ^^^^^
It doesn't make sense that you would read from a pipe and then immediately write the same thing back to the pipe. Also, if you never read from stdin, feof(stdin) will never be true.
Also, with fgets just check for a null result and then outside the loop, do the check for eof:
while (fgets(...) != NULL)
{
...
}
if (!feof(stdin))
{
// error handling
}
mkfifo() just creates special node in filesystem. And you are free to open it in any way. Actually there are two alternatives - POSIX "non-buffered" I/O: open()/write()/read() or standard buffered I/O: fopen()/fread()/fwrite(). First family operates on file descriptors while second one uses so called file streams: FILE. You can not mix these APIs freely. Just choose one and stick to it.
Standard I/O library offers some useful extra capabilities comparing to low-level non-buffered I/O. Like fgets() that you're trying to use. In this situation would be reasonable to use standard streams and replace open() with:
FILE* stream = fopen(FIFO_PATH, "r+");
Thus program will use FILE* instead of plain file descriptors. Also write() need to be changed to fwrite() immediately followed by fflush() to guarantee that written data are passed to FIFO.
P.S. In case of necessity it is possible to "wrap" low-level descriptors returned by open()(or something other) with standard FILE*. See fdopen(). But it is much like a workaround to use standard I/O API with special file objects that can not be opened with fopen().
Any idea why I get 0.000000 with this printf? I checked the file and it was created fine
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
double doub1;
FILE *p;
if((p=fopen("data.txt","wb+"))==NULL)
puts("no");
fprintf(p,"%lf#%lf\n%lf%s",3.9458,314.32133,32.3,"hello");
fscanf(p,"%lf",&doub1);
printf("%lf",doub1);
}
To write to a stream opened with + and read from the same stream you need to flush the output first:
fflush(p);
However this does not reposition the file position indicator. To read characters you already wrote, you need to seek back to them. There is not a separate file position indicator for reading and writing:
fseek(p, 0, SEEK_SET); // go to start of file
The fseek does an implicit flush so you don't need to do fflush if you are doing fseek.
Also, you should check the return value of fscanf before trying to print the output. If the scan failed then you are printing an uninitialized variable.
I am trying to understand the standard I/O. I met a problem of calling fdopen().
What's the behavior if I call fdopen() on the same file descriptor as follows? Why do I get an ouput of '\377' (-1) ?
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
int fd1, fd2;
char c;
FILE *fp1, *fp2;
fd1 = open("foo.txt", O_RDONLY, 0);
fp1 = fdopen(fd1, "r");
fp2 = fdopen(fd1, "r");
if (fp2 == NULL)
printf("NULL\n");
if (errno)
printf("ERROR\n");
c = fgetc(fp1);
c = fgetc(fp2);
printf("c = %c\n", c);
exit(0);
}
Let's say your stdio buffer size is 4K. The first fgetc reads 4K into the buffer and returns the first byte. The fd is now advanced 4K into the file. The second fgetc reads from there. Your file is smaller than the buffer size, so you're at EOF. You print the EOF with %c and get a funny character.
Multiple fdopen on a single fd gets a vote of don't try it; it will hurt from me. With an exception for creating stdin, stdout, and stderr from a single tty descriptor if you're writing getty.
Multiple problems:
char is not the right type for storing the return value of fgetc. Use int.
You're accessing the same open file description via two different handles without performing the steps necessary to switch between them legally. This invokes undefined behavior.
Checking errno and inferring from it that there was an error is not valid. If you already know there was an error, errno tells you which one. It does not tell you whether or not an error occurred, and in case one did not, any nonzero value may have been written to errno.
We don't know your file contents so we can't know what you expect to be read.
In the file "file1.dat" I wrote "anahasapples". And then I wrote this program:
#include <stdio.h>
#include <conio.h>
int main()
{
FILE *ptr_file;
ptr_file=fopen("file1.dat","r+");
printf("%c",fgetc(ptr_file));
printf("%c",fgetc(ptr_file));
printf("%c\n",fgetc(ptr_file));
char c;
printf("char:\n");
c=getch();
fputc(c,ptr_file);
return 0;
}
The part where I print the first 3 characters from the file works. After that, I want to put a char into the file. When I compile this, I don't get any errors, but the containing text doesn't change.
Documentation for fopen() standardly shows the following explanation:
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, output must not be
directly followed by input without an intervening call to fflush(3C)
or to a file positioning function (fseek(3C), fsetpos(3C) or
rewind(3C)), and input must not be directly followed by output without
an intervening call to a file positioning function, unless the
input operation encounters end-of-file.
Just add an fseek() to your code and all works well:
#include <stdio.h>
#include <conio.h>
int main()
{
FILE *ptr_file;
ptr_file=fopen("file1.dat","r+");
printf("%c",fgetc(ptr_file));
printf("%c",fgetc(ptr_file));
printf("%c\n",fgetc(ptr_file));
char c;
printf("char:\n");
c=getch();
fseek( ptr_file, 0, SEEK_CUR ); /* Add this line */
int err = fputc(c,ptr_file);
printf ("err=%d\n", err);
return 0;
}
Here's my file1.dat before and after inputting an 'x':
Before
anahasapples
After
anaxasapples
It seems that by default the fputc() tries to write past the end of the file, so you need to reposition the file pointer (e.g., using fseek) to make the write occur at the point of the current file pointer.
set the pointer first
fseek(ptr_file, ftell (ptr_file), SEEK_SET);
fputc(c,ptr_file);
See this link for explanation http://cplus.about.com/od/learningc/ss/files_8.htm
http://www.rainydayz.org/beej/bgc/fseek.html
Yesterday in my class we started working with files for the first time. I wanted to see how it works, so I made a program where I write a word and that word has to be written in a certain file(that part worked). After that, I wanted to read from that file a number of characters and show it on the screen.
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <sys/stat.h>
#include <process.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int df,m;
char c[50],d[50];
printf("c= \n");
gets(c);
m=strlen(c);
df=open("e:\\codeblocks\\fisperimente\\text2.txt",O_RDONLY|O_WRONLY);
if (df==-1) {printf("error");exit(1);}
write(df,c,m);
/*int i,n;
n=read(df,d,5);
for (i=1;i<=n;i++)
{
printf("%c",d[i]);
} */
close(df);
return 0;
}
What I put in my commentary is the part that doesn`t work. I noticed that if I printf n, it returns -1, which means that I did something wrong while reading from the file.
First, I would avoid gets() at all costs. It is unsafe, and is considered deprecated. It may be removed in the future. Instead, consider using fgets(), like so:
fgets(c, sizeof(c), stdin);
Next, your open is suspicious:
df=open("e:\\codeblocks\\fisperimente\\text2.txt",O_RDONLY|O_WRONLY);
Read only and write only are mutually exclusive. If you want to open a file for both read and write, you need O_RDWR.
And finally, after you write to your file, the file pointer points to the end of file. If you want to reread it, you need to seek back to the beginning. This will do that:
lseek(df, 0, SEEK_SET);
Once you do that, you can read your file back in.
You need to seek to the beginning of the file, to read it's contents back. Or you can just close it or open it again for reading.
Try use flag O_RDWR, the or'd result of read only and write only flags is not what you think it does ;)
Note that mode O_RDWR is not usually equal to O_RDONLY | O_WRONLY. Therefore, you probably opened the file with O_WRONLY (classically, O_RDONLY is 0). This is not yet your major problem; it will become one.