Reputation: 1
I am new to C programming and am trying to execute the code below.
My objective is to create a program that continuously polls on an input file, reads it when it is modified and writes the contents to a new output file.
The program writes to the output file if there is no 'while(1)' loop but it doesn't write to the output file (though the contents have been read) in the infinite loop. Could you please guide me where I am wrong?
void main(){
struct stat time_buf;
time_t input_timestamp=0;
while(1){
if(access( "inpfile.txt", F_OK ) != -1){
sleep(5);
stat("inpfile.txt", &time_buf);
if(time_buf.st_mtime > input_timestamp){
FILE *fpi,*fpo;
long length;
char *buffer=0;
fpi = fopen("inpfile.txt","r");
fseek(fpi,0,SEEK_END);
length=ftell(fpi);
fseek(fpi,0,SEEK_SET);
buffer=(char *)malloc(length);
fread(buffer,1,length,fpi);
fclose(fpi);
fpo=fopen("outfile.txt","w+");
fwrite(buffer,sizeof(char),length,fpo);
fclose(fpo);
input_timestamp=time_buf.st_mtime;
}
}
}
}
Upvotes: 0
Views: 554
Reputation: 1
None of this is really going to answer your problem directly, since you don't really state anything other than your code isn't working. What do you think a car mechanic would ask you if you told him, "My car isn't working."
For example, you're not telling us if the modification time reported by your call to stat()
changes when you think the file contents change.
First, the call to access()
is worse than useless:
if(access( "inpfile.txt", F_OK ) != -1){
.
.
.
That call does you no good, and it introduces the possibility of a TOCTOU bug. Just open the file - don't check if it exists first. If it doesn't exist, opening the file will fail with an ENOENT
or similar value in errno
.
Trying to somehow check if something you plan to do later will work is almost always a bad idea. "I want to check if the file exists before I try to open it." or "I want to ping the server to make sure it's alive before I try to connect to it." are BAD IDEAS. They not only introduce a race condition if the situation changes between the check and the action (what happens if the file is deleted between your access()
call and the fopen()
call?), the check has to differ from your intended action in some way otherwise it would be the action. And since it's different, different rules apply. A fully-functional server may be configured to not respond to pings, for example. So the check can fail in situations where the action itself would actually work. And the other way around - the check can work and then the action can fail.
Don't check. Just do. And then handle all errors.
Second, since you're using stat()
to get the file's modification time, there's no need to use fseek()
/ftell()
to get the size of the file as there's an st_size
field in struct stat
that tells you the file size.
This will copy a file in one step (note that there's no error checking at all, and I used open()
/read()
/write()
instead of fopen()
/fread()
/fwrite()
since you're already using POSIX functions - that allows using fstat()
on the file descriptor instead of stat()
on the input file name, meaning that name only has to be used once:
struct stat sb;
int fd = open( inputFileName, O_RDONLY );
fstat( fd, &sb );
char *data = malloc( sb.st_size );
read( fd, data, sb.st_size );
close( fd );
fd = open( outputFileName, O_WRONLY | O_CREAT | O_TRUNC, 0644 );
write( fd, data, sb.st_size );
close( fd );
free( data );
Note that there is no error checking in that code - open()
can fail, malloc()
can fail, read()
and write()
can both be only partially successful (try to write 8 KB, and only 4 KB actually get written), so you have to check return values. I also left out all the necessary header files.
Adapting that code to a loop where you check for a change in the modification time shouldn't be hard.
Third, technically fseek()
/ftell()
to get the size of the file is undefined behavior in C. (I have no idea why it's taught so much. Bad teachers? And if you use it on Windows on files > 2 GB you'll have issues as long
is 32 bits even on 64-bit Windows.)
Streams open in binary mode are not required to support fseek(..., SEEK_END)
- footnote 268 of the C Standard specifically states "Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END)
, has
undefined behavior for a binary stream ...". And ftell()
on a text stream does not represent how many bytes will be read from a file. Per 7.21.9.4 The ftell
function, paragraph 2:
The
ftell
function obtains the current value of the file position indicator for the stream pointed to bystream
. For a binary stream, the value is the number of characters from the beginning of the file. For a text stream, its file position indicator contains unspecified information, usable by thefseek
function for returning the file position indicator for the stream to its position at the time of theftell
call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.
Fourth, you state "though the contents have been read", but from the posted code you can't know that - you don't check any return values. You just make calls and hope they actually work.
You're also at risk of having this question closed as off-topic. One of the reasons for that is:
Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Complete, and Verifiable example.
As one of the comments already noted, you didn't mention your debugging efforts.
And none of this answer gets into the difficulty of actually detecting file system changes and then processing the changed data. It's not easy to do reliably and quickly, and it I'd say it indicates a bad design.
Upvotes: 1
Reputation: 368
You need to use fflush
after the fwrite
.
The fwrite
does not write the data into the real file it write it to a buffer stream and after X time it will update the data or if the stream buffer is full.
Upvotes: 0