I wanted to write, read and print to and from the same file. But when the program executes, it can write but it can't read or print the data I have written. When I execute the program, it stops working after writing to the file. I have verified that the file (penny.txt) contains data after the write operation.
I don't know where this is going wrong - how can I read and print the data?
I'm quite new to this, so please take that in mind when answering.
#include<stdio.h>
int main()
{
char ch;
char penny[50],pen[50];
FILE *Object;
Object = fopen("Penny.txt","w+");
fgets(penny, sizeof penny, stdin);
fprintf(Object,penny);
fscanf(Object,"%s",pen);
printf("%s",pen);
return 0;
}
You're at the end of the file when you call fscanf(). Use fseek to return to the beginning:
/* this ignores a whole host of other issues */
fprintf(Object,penny);
/* optional: fflush(Object); */
/* after the call to fprintf you're at the end of the "stream" in this case,
* go back to the beginning:
*/
fseek(Object, 0, SEEK_SET);
/* now we have something to read! */
fscanf(Object,"%s",pen);
printf("%s\n",pen);
You did not notice this problem due to a complete lack of error checking. fopen, fprintf, and fscanf all have error conditions listed, and all use their return value to signal a problem. You ignore these return values at your own peril.
#include<stdio.h>
int main()
{
//char ch;//unused!
char penny[50],pen[50];
FILE *Object;
Object = fopen("Penny.txt","w+");
fgets(penny, sizeof penny, stdin);
fprintf(Object,"%s", penny);//it troubled indicator(%) is included
fflush(Object);//Buffer flush : So that there is no wrote
rewind(Object);//rewind the position of access to the file
fscanf(Object,"%s",pen);
printf("%s",pen);
return 0;
}
You need to Use fseek() to move back the file current position inside the file.
int fseek ( FILE * stream, long int offset, int origin );
Reposition stream position indicator
Sets the position indicator associated with the stream to a new position.
stream
Pointer to a FILE object that identifies the stream.
offset
Binary files: Number of bytes to offset from origin.
Text files: Either zero, or a value returned by ftell.
origin
Position used as reference for the offset. It is specified by one of the following constants defined in exclusively to be used as arguments for this function:
Constant Reference position
SEEK_SET Beginning of file
SEEK_CUR Current position of the file pointer
SEEK_END End of file
*
try this:
#include<stdio.h>
int main()
{
char ch;
char penny[50],pen[50];
FILE *Object;
Object = fopen("Penny.txt","w+");
fgets(penny, sizeof penny, stdin);
fprintf(Object,penny);//now the file is in EOF
fseek(Object,-1*(strlen(penny),SEEK_CUR);//<===move back |penny| in the file
/* optional or:fseek(Object,0,SEEK_SET);<===move to start of file */
fscanf(Object,"%s",pen);
printf("%s",pen);
return 0;
}
Related
I am new to the C programming language. I am learning file I/O, and am confused with the fseek function. Here is my code
#include <stdio.h>
#include <stdlib.h>
struct threeNumbers {
int n1,n2,n3;
}
int main (){
int n;
struct threeNumbers number;
FILE *filePointer;
if ((filePointer=fopen("\\\\wsl$\\Ubuntu-20.04\\home\\haseeb\\learningC\\file Input and Output\\program2\\program.bin","rb"))==NULL){
printf("error! opening file);
/* if pointer is null, the program will exit */
exit(1);
}
/* moves the cursore at the end of the file*/
fseek(filePointer,-sizeof(struct threeNumbers),SEEK_END);
for(n=1;n<5;++n){
fread(&number,sizeof(struct threeNumbers),1,filePointer);
printf (" n1:%i\tn2:%i\tn3:",number.n1,number.n2,number.n3);
fseek(filePointer,-2*sizeof(struct threeNumbers),SEEK_CUR);
}
fclose(filePointer);
return 0;
}
I know that this program will start reading the records from the file program.bin in the reverse order (last to first) and prints it.
my confusion is I know that "fseek(filePointer,-sizeof(struct threeNumbers),SEEK_END);" will move the cursor at the end of the binary file. What does "fseek(filePointer,-2*sizeof(struct threeNumbers),SEEK_CUR);" do? I think it moves to the current location, but what is the point of the cursor cumming to the current location in this program? Also why is it -2 instead of being just "-sizeof(struct threeNumbers)"?
Disregarding the actual code, this is what fseek() does:
The fseek() function sets the file position indicator for the stream
pointed to by stream. The new position, measured in bytes, is obtained
by adding offset bytes to the position specified by whence. If whence
is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to
the start of the file, the current position indicator, or end-of-file,
respectively. A successful call to the fseek() function clears the
end-of-file indicator for the stream and undoes any effects of the
ungetc(3) function on the same stream.
fseek(filePointer,-sizeof(struct threeNumbers),SEEK_END) will not "move the cursor at the end of the binary file"; it will move it sizeof(struct threeNumbers) before the end of the file.
I have seen programs for file handling and in one of the program using fseek as shown below:
/* This example opens a file myfile.dat for reading.
After performing input operations (not shown), it moves the file
pointer to the beginning of the file.
*/
#include <stdio.h>
int main(void)
{
FILE *stream;
int result;
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
if (fseek(stream, 0L, SEEK_SET)); /* moves pointer to */
/* the beginning of the file */
{ /* if not equal to 0
then error ... */
}
else {
/* fseek() successful */
}
}
Like this can one move the file pointer to the next line immediately after that line
BO_ 377 FC_DM_MISC: 8 FC
SG_ DATA3 m11 : 31|8#0+ (1,0) [0|0] "" DM
These are the two lines and I want to program in a way that when one identifies the number 377 the pointer should now go to the next line i.e., to the line SG_ DATA3 inspite of the white spaces after 8 FC. How can one do that using fseek in C?
Try this code . It may help you .Here the Each line of the Input file is converted to string ,since string manipulation is very simple comparing to complex fseek() function.This may not be perfect answer but this will be very simple solution.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *stream;
int result;
char tmp[100]; // assuming that max length of a line in myfile.dat is 100.
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
fscanf(stream, "%100[^\n]", tmp); // assuming that max length of a line in myfile.dat is 100.
printf("%s", tmp);
if (strstr(tmp, "377"))
{ // check for 337
fscanf(stream, "%100[^\n]", tmp); // next line is in the string tmp .
// continue your program.
//printf("%s", tmp);
}
}
}
fseek is used for binary data, if you work on a text file you should use either fgets or getline(recommended to use getline).
There's an open discussion of "fgets() vs getline" and many say that "fgets is deprecated" is only a gcc propaganda in favor to their specific getline().
A possible flaw in fgets() is that it doesn't tell you anything if there are null bytes being read, something you can get away with getline().
But then again if you don't like gcc, or use something different, use fgets(). If you are stuck with gcc, then use getline().
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
When I am using fgetpos(fp,&pos), the call is setting pos to a negative value where pos is of type fpos_t. Can some one explain why this is happening?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAX_TAG_LEN 50
char filename[1000] = "d:\\ire\\a.xml";
//extract each tag from the xml file
int getTag(char * tag, FILE *fp)
{
//skip until a beginning of a next
while(!feof(fp))
if((char)fgetc(fp) == '<')break;
if(!feof(fp)){
char temp[MAX_TAG_LEN]={0};
char *ptr;
int len;
fpos_t b;
fgetpos(fp,&b); // here the b is containing -ve values.....???
fread(temp,sizeof(char),MAX_TAG_LEN - 1,fp);
temp[MAX_TAG_LEN-1] = 0;
ptr = strchr(temp,'>'); //search of ending tag bracket
len = ptr - temp + 1;
sprintf(tag,"<%.*s",len,temp); //copy the tag
printf("%s",tag); //print the tag
b += len; //reset the position of file pointer to just after the tag character.
fsetpos(fp,&b);
return TRUE;
}
else{
return FALSE;
}
}
int main()
{
int ch;
char tag[100]={0};
FILE *fp = fopen(filename,"r");
while(getTag(tag,fp)){
}
fclose(fp);
return 0;
}
where a.xml is a very basic xml file
<file>
<page>
<title>AccessibleComputing</title>
<id>10</id>
<redirect />
<revision>
<id>133452289</id>
<timestamp>2007-05-25T17:12:12Z</timestamp>
<contributor>
<username>Gurch</username>
<id>241822</id>
</contributor>
<minor />
<comment>Revert edit(s) by [[Special:Contributions/Ngaiklin|Ngaiklin]] to last version by [[Special:Contributions/Rory096|Rory096]]</comment>
<text xml:space="preserve">#REDIRECT [[Computer accessibility]] {{R from CamelCase}}</text>
</revision>
</page>
</file>
The code is working for some xml files but for the above xml file it is stoping after printing the first tag.
According to the cplusplus.com description of fpos_t:
fpos_t objects are usually created by a call to fgetpos, which returns a reference to an object of this type. The content of a fpos_t is not meant to be read directly, but only to use its reference as an argument in a call to fsetpos.
I think that means that in theory the value of an fpos_t could be arbitrarily positive or negative, so long as the implementation treats it correctly. For example, fpos_t could be some offset from the end of the file rather than the beginning, in which case negative values make sense. It also could be some weird bit-packed representation that would use each bit, including the sign bit, to encode some other information about the file position.
Finally I found the error....
msdn says
You can use fseek to reposition the
pointer anywhere in a file. The
pointer can also be positioned beyond
the end of the file. fseek clears the
end-of-file indicator and negates the
effect of any prior ungetc calls
against stream.
When a file is opened for appending
data, the current file position is
determined by the last I/O operation,
not by where the next write would
occur. If no I/O operation has yet
occurred on a file opened for
appending, the file position is the
start of the file.
For streams opened in text mode, fseek has limited use, because
carriage return–linefeed translations
can cause fseek to produce unexpected
results. The only fseek operations
guaranteed to work on streams opened
in text mode are:
Seeking with an offset of 0 relative
to any of the origin values. Seeking
from the beginning of the file with an
offset value returned from a call to
ftell.
once fopen call is modified from "r" to "rb" it worked fine....
thanks
I'm trying to read from stdin and output the data, things work, EXCEPT that it's not outputting the new incoming data. I'm not quite sure where is the issue. I'm guessing it has something to do when determining the stdin size. Any help would be greatly appreciated! Thanks
tail -f file | my_prog
Updated
#include <stdio.h>
#include <sys/stat.h>
long size(FILE *st_in) {
struct stat st;
if (fstat(fileno(st_in), &st) == 0)
return st.st_size;
return -1;
}
int main (){
FILE *file = stdin;
char line [ 128 ];
while ( fgets ( line, sizeof line, file ) != NULL )
fputs ( line, stdout ); /* write the line */
long s1, s2;
s1 = size(file);
for (;;) {
s2 = size (file);
if (s2 != s1) {
if (!fseek (file, s1, SEEK_SET)) {
while ( fgets ( line, sizeof line, file ) != NULL ) {
fputs ( line, stdout ); /* write the line */
}
}
s1 = s2;
usleep(300000);
}
}
return 0;
}
Edit: Fixed!
After a FILE * has reached EOF, it stays in a state where it will read no more data until you clear the 'EOF' bit either with clearerr() or with fseek(). However, if standard input is connected to a terminal, then that is not a seekable device, so instead of clearing the error, it might not do anything useful:
POSIX says:
The behavior of fseek() on devices which are incapable of seeking is implementation-defined.
Your loop entry condition is suspect; you need to sleep before starting it, and you need to sleep on each iteration. Indeed, normally you write tail -f without worrying about the file size; you sleep, try to read until the next 'EOF', reset the file EOF indicator, and repeat. Note, too, that the size of a pipe or terminal is not defined.
Separately, it is aconventional to call a FILE * argument to a function filename; it has completely the wrong connotations. A filename is a string.
This is not really standard C:
size(file);
Call stat() to get file information - organization type of a file, file size and permissions.
What your code does is to eventually set the file pointer to the end of the file, as it tries to read through it. Consider stat() (or fstat() on a an open file) instead.
rewind() resets the file pointer to the start of the file, fseek() will place it anywhere you need.
tail -f repeatedly tries the file at the EOF point with a short sleep in between tries.... It does not "consider" EOF to be an error. It remembers the current file offset for the EOF, then fseeks() using SEEK_END, then calls ftell(), and compares the offsets. If there is a difference it then fseek()-s back to the last known endpoint and reads the data.
This description is from old unix source. I'm sure it has been tweaked since then.