I don't udnerstand that.
The File exists. It has contant which length is fitting the value hold by sizeIndexI.
I'm at the begining of the File(Am I not?) and anyway It wont read from that file...
Ofc. the file also was succesfully opened before. (In this case with a+) And the access permissions for the File are ofc. also given.
fpNewsPageLogger = fopen ("/NewsLogx", "a+");
if (fpNewsPageLogger == nullptr)
{
/*...*/
}
else
{
fseek (fpNewsPageLogger, 0 ,SEEK_END);
sizeIndexI = ftell (fpNewsPageLogger);
rewind (fpNewsPageLogger);
DebugLogMsg10 (pDebugLogger, sizeThreadID, "ReadAmount:%d IndexI:%d!", sizeBytesRead, sizeIndexI);
cpTmpNews = calloc (sizeIndexI, sizeof(char));
if (cpTmpNews == nullptr)
{
fclose (fpNewsPageLogger);
return;
}
sizeBytesRead = fread (cpTmpNews, sizeof (char), sizeIndexI, fpNewsPageLogger);
/*...*/
}
Is there anything I'm not thinking about?
Firstly, standard library is not required to meaningfully support seeking from SEEK_END. Did you check the value of sizeIndexI? Maybe it is simply zero? If you ask fread to read zero elements, it expectedly returns zero.
Secondly, you are opening your stream as a text stream. For a text stream values returned by ftell do not generally have any meaningful numerical semantics. In general case ftell for text streams returns an implementation defined encoding of the current position, not the byte offset from the beginning of the file. If you want to work with your stream as binary stream, add "b" to fopen
fpNewsPageLogger = fopen ("/NewsLogx", "ab+");
Related
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
fp = fopen("clients.dat", "wb");
fclose(fp);
fp = fopen("clients.dat", "rb");
while (1) {
if (fp == EOF)
break;
else
printf("There is something inside a file");
}
fclose(fp);
return 0;
}
Here comes a question: what do empty binary files contain? should the pointer point to the EOF character? I mean: isn't it that the first and last thing in the file is EOF? OR how Can I check whether a file is empty or not?
An empty file contains nothing, it is empty. So it contains 0 bytes. EOF is not a character that is at the end of a file, it is an integer constant used as return value from some of the standard methods reading from a file to indicate end of file or some sort of error.
When you open a file you get a pointer to a FILE type back, this is what you can expect even from an empty file.
A file is not terminated the same way a string is, so there is no equivalent of a NULL character in a file, that determines when the file contents stops.
To determine whether a file you have opened and have a valid FILE pointer to is empty you can use fseek and ftell:
fseek(fp, 0, SEEK_END);
size = ftell(fp);
if (size == 0) {
// File is empty
}
Function fopen returns a pointer to a file handle of type FILE, not a pointer to any content of the file or a pointer to an EOF-character. The pointer is NULL if the file could not be opened at all, but does not indicate whether the file is empty or not.
To check if a file is empty you either (1) need to make an attempt to read bytes and handle the various results, or (2) to use fseek and ftell to move the read pointer to the end and ask then for the position.
(1)
fp=fopen("clients.dat","rb");
char buffer;
size_t bytesRead = fread(&buffer, 1, 1, fp); // try to read one byte
if(bytesRead == 1) {
printf("file contains at least one byte\n");
} else { // error handling
if (feof(fp))
printf("Attemt to read though end of file has been reached. File is empty.\n");
else if (ferror(fp)) {
perror("Error reading file.");
}
}
(2)
fp=fopen("clients.dat","rb");
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
if (size==0) {
// file is empty.
}
I'd prefer the second variant.
Here's another approach:
To check if the file is empty, you can simply read the file:
int c = fgetc(fp);
if (c == EOF)
{
// The file is empty or an error occured
if (feof(fp))
{
// Empty
}
else
{
// Error during file read
}
}
else
{
// non-empty file
}
Here comes a question what empty binary files contain ?
Empty files contain nothing, that is what makes them empty.
Regular files have a size which is not part of their data, but instead is normally a part of the directory entry or inode.
should the pointer point to the EOF character ?
No
First of all the pointer returned by fopen is NOT a pointer to the content of the file, but merely a pointer to a data structure describing the open file.
Secondly EOF is not an actual part of the file, but a special return value from the getc family of functions used to indicate that the end of file has been reached.
To test whether you are at the end of a file without reading from it you can use the feof function.
I have a function like this which aims to read a file:
int foo(FILE* f)
I want to use flock in order to prevent TOCTTOU. flock requires a file descriptor as an integer. I can get this using fileno(file). The implementation of foo therefore might look like this:
int foo(FILE* f) {
if(!f) return -1;
int fd = fileno(f);
if(fd < 0) return -1;
flock(fd, LOCK_EX);
//do all the reading stuff and so on.
}
However, the evil user might do something like this:
FILE* test;
test = fopen("someexistingfile.txt", "r");
fclose(test);
foo(test);
Then I have a problem because fileno will do invalid reads according to valgrind because it assumes that the file is open.
Any ideas on how to check whether the file is closed?
C11 n1570 7.21.3p4
A file may be disassociated from a controlling stream by closing the file. Output streams are flushed (any unwritten buffer contents are transmitted to the host environment) before the stream is disassociated from the file. The value of a pointer to a FILE object is indeterminate after the associated file is closed (including the standard text streams). Whether a file of zero length (on which no characters have been written by an output stream) actually exists is implementation-defined.
After fclose the use of the value of a FILE * in library functions leads to undefined behaviour. The value of the pointer cannot be used safely for anything at all until reassigned.
In other words, you cannot do really anything at all to discern whether the FILE * value you've given refers to a valid open file or not... well except for testing against NULL - if the value of the pointer is NULL it certainly cannot point to an open stream.
A program that runs just fine on my freeBSD system fails when I build it on windows (Visual Studio 15). It goes into an endless loop here:
//...
while (1) {
if ('#' == fgetc(f)) {
// we do some stuff here. irrelevant for stackoverflow question
break;
}
fseek(f, -1, SEEK_CUR);
if (0 != fseek(f, -1, SEEK_CUR)) {
// Beginning of file.
break;
}
}
//...
On closer look (by adding a bunch of fgetpos()-calls) I find that fgetc moves the file position indicator backwards. So it misses the beginning of the file and some '#' if they are not in a multiple-of-3 position from the end.
I notice that this only happenes when the file f is opened with
fopen(filename, "a+");
//text mode read/append
When I change it to
fopen(filename, "ab+");
//binary mode read/append
then everything works as expected.
I think for my code it is safe just to use binary mode all the time.
But two questions remain:
Are there reasons that stand against binary mode?
What trickery is this with wrong direction in text mode?
Quoting C11 7.21.9.2 the fseek function:
For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET.
Invoking fseek with a whence argument of SEEK_CUR on a stream open in text mode is not covered by the C Standard. Opening the file in binary mode seems a much better option.
The value returned by fgetpos() may not be meaningful as an offset in the file, it is only meant to be passed as an argument to fsetpos().
As a general remark, you should try and change you algorithms to avoid relying on backwards seeks in the stream, especially relying on fseek() errors seems unreliable. Instead save the position before the fgetc() with ftell() or fgetpos() and restore it when needed with fseek(pos, SEEK_SET, fp) or fsetpos().
After opening a file in append update mode, is it necessary to execute a file positioning statement before each write to the file?
FILE *h;
int ch;
if ((h = fopen("data", "a+")) == NULL) exit(1);
if (fseek(h, 0 SEEK_SET)) exit(2);
ch = fgetc(h); /* read very first character */
if (ch == EOF) exit(3);
/* redundant? mandatory? */
fseek(h, 0, SEEK_END); /* call file positioning before output */
/* add 1st character to the end of file on a single line*/
fprintf(h, "%c\n", ch);
The C11 Standard says:
7.21.5.3/6 ... all subsequent writes to the file to be forced to the then current end-of-file ...
and
7.21.5.3/7 ... input shall not be directly followed by output without an
intervening call to a file positioning function ...
I take it the shall in 7.21.5.3/7 is stronger than the description in 7.21.5.3/6.
Probably not redundant in portable C. While the underlying file descriptor will always append (at least on Unix), the point of the fseek/fflush requirement is to get rid of the input buffer before writing to the output, so that the same buffer can be used for reading and writing. AFAIK you're not even required to seek to end of file, you can seek anywhere, as long as you seek.
The second description is stronger than the first, but that is to be expected. The first only states that all writes go to EOF, i.e. that there's no way to write anywhere else. The second establishes the rule that switching from reading to writing must be accompanied by a flush or seek, to ensure that read and write aspects of the buffer don't get mixed up.
I wish to open a file using the "a+b" mode, i.e. if it does not exist it is created automatically, but if it does I don't want to overwrite it. I want to be able to read and write to the file.
The file is binary, and I want to save records of a specific struct in it. So I want to do fseek() to the record I want and then save the record using fwrite().
The code looks as follows (MyRecord is a typedef to a struct, while FILENAME is a #define to the file's name):
int saveRecord(MyRecord *pRecord, int pos)
{
FILE* file = fopen(FILENAME, "a+b");
if (file == NULL)
{
printf("Unable to open file %s\n", FILENAME);
return 0;
}
fseek(file, pos * sizeof(MyRecord), SEEK_SET);
fwrite(pRecord, sizeof(MyRecord), 1, file);
fclose(file);
return 1;
}
However this code just appends the record to the end of the file, even if I set pos to 0. Why isn't fseek() with SEEK_SET working in append mode?
I know I can simply open it with "r+b" and if it fails open it with "wb", but I want to know why this doesn't work and why fseek() with SEEK_SET is leaving the file pointer at the end. Any references to places where this behaviour is documented appreciated (because I couldn't find any, or I am using the wrong keywords).
That's because in a mode, writing to the FILE* always appends to the end. fseek only sets the read pointer in this mode. This is documented in the C standard, 7.19.5.3 fopen:
Opening a file with append mode ('a' as the first character in the mode argument)
causes all subsequent writes to the file to be forced to the then current end-of-file,
regardless of intervening calls to the fseek function.
Plain C does not have any sane way to achieve what you want. If you're on a POSIX system or anything remotely close, you can use fd=open(FILENAME, O_CREAT|O_RDRW, 0666) and then fdopen(fd, "rb+").
Edit: Another thing you could try, with plain C:
f = fopen(FILENAME, "a+b");
if (!f) /* ... */
tmp = freopen(0, "r+b", f);
if (tmp) f = tmp;
else /* ... */
Use "r+b" mode and fallback to "w+b" if it fails.
The "a+b" mode, allows you to read and append; the "r+b" allows random read and write.
The documentation for fopen describes how the file behaves with the different modes.