How does fread know where it last stopped? - c

Fread apparently knows the place where it last stopped, by that I mean this:
while(fread(buffer, 1, 1, file))
{
…
}
This loop would continue the next time where it stopped the last time. I assume it just moves the file pointer forward, but could someone explain if it’s exactly like that?

The function fread reads from a stream, which is not necessarily a file. Streams can also be linked to consoles/terminals. Some streams are seekable and have a file position indicator, some do not. Streams which are linked to actual files usually do have a file position indicator.
The function fread itself does not advance any file position indicator (it does not call fseek). It just reads from the stream.
If a stream has a file position indicator, then the runtime library will advance the file position indicator, whenever a read takes place on the stream. It does this for all reads on the stream, not just for fread.

Related

Can I read from the beginning a file open for append mode without an initial fseek()?

When an existing non empty file is successfully opened by fopen() in "a+" or "ab+" mode, I should be able to read from it or write to the end without an initial call to fseek() or rewind(). Does the C Standard specify that an initial read from this file will read from the beginning of the file or should I always set the file position before reading?
The C Standard seems ambiguous as it states in 7.21.5.2 the fopen function that:
6. 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. In some implementations, opening a binary file with append mode (b as the second or third character in the above list of mode argument values) may initially position the file position indicator for the stream beyond the last data written, because of null character padding.
On those systems where the file position indicator would point at or beyond the last data written, would an initial reading operation fail?
The behavior is implementation defined:
7.21.3 Files
1 A stream is associated with an external file (which may be a physical device) by opening a file, which may involve creating a new file. Creating an existing file causes its former contents to be discarded, if necessary. If a file can support positioning requests (such as a disk file, as opposed to a terminal), then a file position indicator associated with the stream is positioned at the start (character number
zero) of the file, unless the file is opened with append mode in which case it is implementation-defined whether the file position indicator is initially positioned at the beginning or the end of the file. The file position indicator is maintained by subsequent reads, writes, and positioning requests, to facilitate an orderly progression through the file.
So a call to rewind() or fseek(fp, 0L, SEEK_SET) is required before an initial read from the beginning of a file open for update mode/write to the end, as determined by a mode string starting with "a+" or "ab+".

c language : fwrite doesnt do anything

{
FILE* f1 = fopen("C:\\num1.bin", "wb+");//it will create a new file
int A[] = { 1,3,6,28 }; //int arr
fwrite(A, sizeof(A), 1, f1); //should insert the A array to the file
}
I do see the file but even after the fwrite, the file remains empty (0 bytes), does anyone know why?
You need to close the file with fclose
Otherwise the write buffer will not (necessarily) force the file contents to be written to disk
A couple of things:
As #Grantly correctly noted above, you are missing a call to fclose or fflush after writing to the file. Without this any cached/pending writes will not necessarily be actually written to the open file.
You do not check the return value of fopen. If fopen fails for any reason it will return a NULL pointer and not a valid file pointer. Since you're writing directly to the root of the drive C:\ on a Windows platform, that's something you definitely do want to be checking for (not that you shouldn't in other cases too, but run under a regular user account that location is often write protected).
Result of fwrite is not required to appear in the fille immediately after it returns. That is because file operations usually work in a buffered manner, i.e. they are cached and then flushed to speed things up and improve the performance.
The content of the file will be updated after you call fclose:
fclose()
(...) Any unwritten buffered data are flushed to the OS. Any unread buffered
data are discarded.
You may also explicitly flush the internal buffer without closing the file using fflush:
fflush()
For output streams (and for update streams on which the last operation
was output), writes any unwritten data from the stream's buffer to the
associated output device.

What exactly does rewind() do?

I came across the rewind() function in C. I went through its description and example from here.
The description mentioned the following about the function:
The C library function void rewind(FILE *stream) sets the file position to the beginning of the file of the given stream.
I really didn't get the idea clear yet. Can we imagine it as a cursor moving in the file to be read, and rewind() simply sets that cursor to the beginning of the file?
From the man page:
The rewind() function sets the file position indicator for the stream pointed to by stream to the beginning of the file. It is equivalent to:
(void)fseek(stream, 0L, SEEK_SET)
except that the error indicator for the stream is also cleared (see
clearerr(3)).
So the next time you read from a file after calling rewind, you start reading from the beginning. So your cursor analogy is a valid one.

Does fread() advances the pointer after it finishes reading the file?

I'm trying to read from a file in C and after I'm done reading want to write to the same file. I'm trying to use fread() for this. Does anyone know if fread advances the pointer after it encounters "\0"? I mean after I finish reading do I need to advance the pointer or do I need to straight-away start writing into the file using fwrite ?
fread will advance the file position (not pointer) until it hits EOF.
However, it will not stop reading simply because it encounters '\0'. In fact, even fgets will only stop reading when it encounters \n. No standard library function I know of stops reading a file at '\0'.
Yes, it does advance the pointer unless you meet EOF or encounter an error:
RETURN VALUES
The functions fread() and fwrite() advance the file position indicator for the stream by the number of bytes read or written. They return
the number of objects read or written. If an error occurs, or the end-of-file is reached, the return value is a short object count (or
zero).

unistd.h read() function: How to read a file line by line?

What I need to do is use the read function from unistd.h to read a file
line by line. I have this at the moment:
n = read(fd, str, size);
However, this reads to the end of the file, or up to size number of bytes.
Is there a way that I can make it read one line at a time, stopping at a newline?
The lines are all of variable length.
I am allowed only these two header files:
#include <unistd.h>
#include <fcntl.h>
The point of the exercise is to read in a file line by line, and
output each line as it's read in. Basically, to mimic the fgets()
and fputs() functions.
You can read character by character into a buffer and check for the linebreak symbols (\r\n for Windows and \n for Unix systems).
You'll want to create a buffer twice the length of your longest line you'll support, and you'll need to keep track of your buffer state.
Basically, each time you're called for a new line you'll scan from your current buffer position looking for an end-of-line marker. If you find one, good, that's your line. Update your buffer pointers and return.
If you hit your maxlength then you return a truncated line and change your state to discard. Next time you're called you need to discard up to the next end of line, and then enter your normal read state.
If you hit the end of what you've read in, then you need to read in another maxline chars, wrapping to the start of the buffer if you hit the bottom (ie, you may need to make two read calls) and then continue scanning.
All of the above assumes you can set a max line length. If you can't then you have to work with dynamic memory and worry about what happens if a buffer malloc fails. Also, you'll need to always check the results of the read in case you've hit the end of the file while reading into your buffer.
Unfortunately the read function isn't really suitable for this sort of input. Assuming this is some sort of artificial requirement from interview/homework/exercise, you can attempt to simulate line-based input by reading the file in chunks and splitting it on the newline character yourself, maintaining state in some way between calls. You can get away with a static position indicator if you carefully document the function's use.
This is a good question, but allowing only the read function doesn't help! :P
Loop read calls to get a fixed number of bytes, and search the '\n' character, then return a part of the string (untill '\n'), and stores the rest (except '\n') to prepend to the next character file chunk.
Use dynamic memory.
Greater the size of the buffer, less read calls used (which is a system call, so no cheap but nowadays there are preemptive kernels).
...
Or simply fix a maximum line length, and use fgets, if you need to be quick...
If you need to read exactly 1 line (and not overstep) using read(), the only generally-applicable way to do that is by reading 1 byte at a time and looping until you get a newline byte. However, if your file descriptor refers to a terminal and it's in the default (canonical) mode, read will wait for a newline and return less than the requested size as soon as a line is available. It may however return more than one line, if data arrives very quickly, or less than 1 line if your program's buffer or the internal terminal buffer is shorter than the line length.
Unless you really need to avoid overstep (which is sometimes important, if you want another process/program to inherit the file descriptor and be able to pick up reading where you left off), I would suggest using stdio functions or your own buffering system. Using read for line-based or byte-by-byte IO is very painful and hard to get right.
Well, it will read line-by-line from a terminal.
Some choices you have are:
Write a function that uses read when it runs out of data but only returns one line at a time to the caller
Use the function in the library that does exactly that: fgets().
Read only one byte at a time, so you don't go too far.
If you open the file in text mode then Windows "\r\n" will be silently translated to "\n" as the file is read.
If you are on Unix you can use the non-standard1 gcc 'getline()' function.
1 The getline() function is standard in POSIX 2008.
Convert file descriptor to FILE pointer.
FILE* fp = fdopen(fd, "r");
Then you can use getline().

Resources