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.
Related
I can examine a file's permission bits using the stat() system call, which returns a struct, which contains a field that in turn contains the file type and mode. Is there a way to do the same using nothing but the open and read syscalls? I.e. by analyzing each bit? For example the following code reads a file (the first four bytes) and determines whether it's an ELF file or not ..
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd = open("main", O_RDONLY);
char *buf = malloc(sizeof (char) * 4);
read (fd, buf, 4);
if (strcmp(buf, "ELF"))
printf("It is an ELF file.\n");
free(buf);
return 0;
}
Is there a similar way to read a file to extract the information bit-by-bit?
File permissions are not part of the file's contents but part of its directory entry, therefore you can't read the permissions using open or read on the file.
Using stat is the proper way to do this.
I saw that you mentioned in another comment that you're doing this for learning purposes only. Anyone else reading this for production work...DONT. It'll be non-portable! You probably just want to use stat on the containing directory.
You're going to want to take a look at your systems definition of the stat function. Here is one example of the stat function implementation. Its definitely not as easy as just calling stat. But if you study this source and follow links in it, you'll get an idea of how it works.
Unfortunately I'm sane enough to not study the source, and am unsure if it can be done with just combinations of open and read. My guess is no, though (just a guess)
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.
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().
So I am trying to do some very simple read/writes on a file. Since it's for an assignment I can't use more sophisticated functions using File*.
I can easily create a file and write to it but if I try to read back my content (it's the same content but my problem boils down to this) I don't get what I expect and I can't yet see why.
Here the code snippet that causes me problems:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char** argv){
int fdisk = open("testfile.txt", O_RDWR | O_CREAT | O_APPEND);
char buff [20] = "Just a short text!!!";
write(fdisk, buff, sizeof(buff));
char buff2[20];
read((fdisk), buff2, sizeof(buff2));
printf("Context of deleted file: %c\n",buff[1]);
printf("Context of deleted file: %c\n",buff2[1]);
return 0;
}
When you create a file you need to specify the file access mode:
int fdisk = open("testfile.txt", O_RDWR | O_CREAT | O_APPEND, 0666);
Otherwise the access mode is some indeterminate value.
And before reading it back you need to rewind it:
lseek(fdisk, 0, SEEK_SET); // rewind
The problem is that the write call leaves the file descriptor pointing to just after the data written (so more writes will go after that rather than overwriting the same data), so the following read call tries to read data after that which was written, and probably gets nothing.
I think it is a combination of issues:
You are not rewinding or re-opening the file, so when you read you are always reading from the end of the file.
You are using append mode, so it will add data to the end of the file. This means that after the first run you will be writing data at the end of the file but always reading from the beginning (assuming you address the first problem).
You are not setting the permissions, so you get random file permissions and the file may not be readable after creating it.
Your print statement is only printing the second character from each buffer, rather than a full string.
Here is a minimal working example. This compiles and runs with the expected results on my machine.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char** argv){
int fdisk = open("testfile.txt", O_RDWR | O_CREAT, 0666);
char buff[] = "Just a short text!!!";
write(fdisk, buff, sizeof(buff));
lseek(fdisk, 0, SEEK_SET);
char buff2[sizeof(buff)];
read((fdisk), buff2, sizeof(buff2));
printf("Context of deleted file: %s\n",buff);
printf("Context of deleted file: %s\n",buff2);
return 0;
}
As a final note, the functions you are using (read/write) all return values indicating whether the operation was successful. You should check them. They would have indicated that the read operation in your problem was not actually reading any data (because it was at the end of the file).
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