C: Synchronising two file pointers to the same file - c

I need two file pointers (FILE *) to operate alongside each other. One is to apply append operations and another is for reading and overwriting.
I need appends to the file from one pointer to be recognised by the other file pointer so that the other file pointer can both correctly read and overwrite this appended data.
To synchronise the data, it appears that using fflush() on the appending file pointer works (at least for reading it does), but is this the correct way to achieve what I want and is it portable?
Thank you.

You should be able to do that with one pointer (and thus not having to sync unnecessarily). Just use fseek(f, SEEK_END, 0); when you want to add at the end. Use "rb+" to make the file readable and writeable.
As long as you don't use multiple threads to access the file, this should work just fine.

Related

Understanding file pointers and buffers

Why, in C, do you need a separate buffer to read a FILE *? When you declare a FILE * and assign to it with fopen, does the file then not exist in contiguous memory starting at the address of said pointer? I'm struggling to make the connection as to why you need need to read via fread() into a separate buffer. If someone could explain how theFIlE *file = fopen(filename, "r") and the subsequent fread(&buffer,...) work in conjunction it would help my understanding tremendously. Thanks in advance.
The FILE * returned by fopen is an unnecessary, but useful, layer of indirection.
Theoretically, fopen could have been designed to read the whole file into a buffer in memory, and just return you that buffer.
The issue approach is that it's not flexible at all. It forces you to read the entire file for all file IO operations, which is very undesirable. For example, here are some problems that would come about:
How could you read a file that's too big to fit in RAM?
What if you just want to append a new line at the end of a file (such as for logging). You would have to read the whole file, append the line at the end, then rewrite the entire file back. Expensive!
What if you're only interested in reading a small part of a file, such as reading the magic number to identify the file's type, without regard for its actual content?
What if you wanted to simultaneously edit the file from multiple programs. Each program need to constantly reread the whole file into memory, to ensure it kept up-to-date.
fopen returns a file handle that identifies a file still on disk. How much you read out of this file into memory is entirely up to you.
The explanation given above is pretty much self explanatory , still I would try to make it simple (in case anyone has problem understanding it)
In Short,consider this example and you yourself would know 'why?'
1) your files might be too large and stored in your hard drive , then if you try reading it frequently, don't you think this is an overhead for loading whole file again and again.
2) And more worse say the file is huge then if you load whole of your file it consumes your RAM even if you don't need whole file at once.
Why, in C, do you need a separate buffer to read a FILE *?
First thing, Because reading into buffers and then using it is always faster.
does the file then not exist in contiguous memory starting at the
address of said pointer?
May or May not be ,depending on its size.
If someone could explain how theFIlE *file = fopen(filename, "r") and
the subsequent fread(&buffer,...) work in conjunction
The fopen() function is used to open a file and associates an I/O stream with it. This function takes two arguments. The first argument is a pointer to a string containing name of the file to be opened while the second argument is the mode in which the file is to be opened.
Various modes can be like r, r+, w, w+, a, a+ .
The fopen() function returns a FILE stream pointer on success while it returns NULL in case of a failure.
Look here for detailed info.
Why, in C, do you need a separate buffer to read a FILE *?
No buffer aren't necessary while they are usually present to accelerate I/Os.
When you declare a FILE * and assign to it with fopen, does the file
then not exist in contiguous memory starting at the address of said
pointer?
Certainly not, 'cause this would be at least inefficient (why read a entire file huge if it is not needed at the end?) and at worst impossible at all (RAM size is usually much less than DISK size).
If someone could explain how the FILE *file = fopen(filename, "r") and
the subsequent fread(&buffer,...) work in conjunction it would help my
understanding tremendously.
Then FILE * is not an handle to a memory object that contains the file data, but is a memory object that contains data to help accessing file data on disk. That opaque object (opaque means don't try to look inside details are hidden) contains for example the current offset (remember when you read or write this is done at a given offset and this would modify the offset accordingly), or the open mode (this way writing into an opened for read file will correctly fails), or some buffer (that may contains part of the file and sometimes the whole file!), etc. A FILE * is handle as a handle for a door. Don't confuse file and FILE*, the first is a generic term to embrace what you already know (data on disk), then second is a type to represent an opened file which is a dynamic object to represent manipulation of a given file.
I'm struggling to make the connection as to why you need need to read
via fread() into a separate buffer.
If you don't have/can't have the file in memory, then you need to ask for reading the part you are interested in.

What is the concept behind file pointer or the stream pointer?

I know that pointer is a variable that stores address of another variable. So i understood the concepts of char type pointers, integer type pointers, what happens when we add one to a pointer etc. But i didn't get the real concept behind file pointer. Why can't we directly point to them as we do in case of character data type? For eg consider a file with content:
Hello World
fantastic
Let 'ptr' point to this file. Why can't we use the technique ptr to point to 'H', (ptr+1) to 'e', (ptr+2) to 'l' and so on. If my question is stupid, forgive sometimes it would becomes clear if i understand the real concept. I think this file is actually stored in memory just like a string is stored in memory.
(I know fscanf() function and all)
There's something called memory mapped file, but this apart, you can achieve what you want (if I understood it correctly) simply opening the file and loading it into a buffer (which is by the way a common way of reading data from files).
Once in memory, you access the first byte with *buf, the second with *(buf+1) and so on; or, usually better since clearer, with buf[0], buf[1] and so on.
Why you can't if you don't use a memory mapped file? Since what you have when you open a file in C (using fopen) is an opaque pointer (i.e. a pointer pointing to data unnknown to you, you must consider it as a "concept" rather than actual data you can read) allowing other functions (fread, fwrite, fseek, and so on) to "operate" on that file you opened, but that pointer does not "contain" the bytes of the file. It is called sometimes handler for a reason: it makes it possibile to "handle" the file.
Using that opaque pointer FILE*, you can read bytes from that file in memory, then you can process the data in memory.
I think you're talking in the context of the C language. No, the file is not actually stored in memory. Think of the file pointer e.g. as a pointer/arrow which shows you how far you're in the process of reading of that file. This means, if you now do a read operation, the pointer tells you which char/int etc. you will read from this file i.e. where you are currently in it. This is what the pointer is for. This is my way of roughly and informally explaining this.
I suppose the basic reason I wouldn't expect ptr+1 to give me the second character of the file is that generally, in C, pointer arithmetic moves you by one object, not one byte; so I would expect ptr+1 to point to the "next" file, whatever that means (if anything).
And files are generally stored on disk, not in memory.
The file is not stored in memory. It can be brought to memory (or parts of it) when you open it. Files are not part of your program's data, they're just an entity you can use with the help of the operating system.
There is a lot more behind files when compared to regular character arrays in memory. Reading from and writing to files is generally buffered, this is handled by the standard C library FILE structure, which lets you invoke operations on a file.
And what would even mean to have a "pointer to a file"? You see, ptr+1 to scan through the file is not a good choice for many reasons. If it's binary data, what exactly do you expect with ptr+1? What if you wanted to read larger chunks of data, like a line at a time?
As you can see, there are several reasons for this choice, the main one being that files are not layed out in memory in your program's address space like regular variables. A structure describing the file and your cursor position is the most common approach.
Another important point to note is that the semantics of ptr+1 make sense for language built-in types only. A file is not a built-in type, and it wouldn't make sense to be.

Where is the FILE struct allocated?

In C, when opening a file with
FILE *fin;
fin=fopen("file.bin","rb");
I only have a pointer to a structure of FILE. Where is the actual FILE struct allocated on Windows machine? And does it contain all the necessary information for accessing the file?
My aim is to dump the whole data segment to disk and then to reload the dumped file back to the beginning of the data segment. The code that reloads the dumped file is placed in a separate function. This way, the fin pointer is local and is on the stack, thus is not being overwritten on reload. But the FILE struct itself is not local. I take care not to overwrite the memory region of size sizeof(FILE) that starts at the address fin.
The
fread(DataSegStart,1,szTillFin,fin);
fread(dummy,1,sizeof(FILE),fin);
fread(DataSegAfterFin,1,szFinTillEnd,fin);
operations completes successfully, but I get an assertion failure on
fclose(fin)
Do I overwrite some other necessary file data other than in the FILE struct?
The actual instance of the FILE structure exists within the standard library. Typically the standard library allocates some number of FILE structures, which may or may not be a fixed number of them. When you call fopen(), it returns a pointer to one of those structures.
The data within the FILE structure likely contains pointers to other things such as buffers. You're unlikely to be able to save and restore those structures to disk without some really deep integration with your standard library implementation.
You may be interested in something like CryoPID which does process save and restore at a different level.
It seems like you're trying to do something dangerous, unlikely to work.
fopen allocates a FILE structure and initializes it. fclose releases it. How it allocates it and what it puts in it is implementation dependent. It could contain a pointer to another piece of memory, which is also allocated somewhere (since it's buffered I/O, I guess it does allocate a buffer somewhere).
Writing code that relies on the internals of fopen is dangerous, most likely won't work, and surely won't be stable and portable.
Well, you have a pointer to a FILE object, so technically you know where it is but you should be aware that FILE is deliberately an opaque type. You shouldn't need to know what it contains, you just need to know that you can pass it to functions that know about it to perform certain actions. Additionally, FILE may not be a complete type so sizeof(FILE) might not be correct and, additionally, the object might contain pointers to other structures. Simply avoiding overwriting the FILE object is not likely to be sufficient for you to avoid corrupting the program by writing over most of its memory.
FILE is defined in stdio.h. It contains all the information about the file but, looking at the code you show, I think you don't understand its purpose. It is created and run through the operating system with the C library which fills FILE with information about the file but it is not contained in the file itself.

How to open a file of any length in C?

As a school assignment I'm tasked with writing a program that opens any text file and performs a number of operations on the text. The text must be loaded using a linked list, meaning an array of structs containing the char pointer and the pointer to the next struct. One line per struct.
But I'm having problems actually loading the file. It seems the memory required to load the text into memory must be allocated before I actually read the text. Hence I have to open the file several times. Once to count the number of lines, then twice per line; once to count the characters in the line then once to read them. It seems absurd to open a file hundreds of times just to read it into memory.
Obviously there are better ways of doing this, I just don't know them :-)
Examples
Can the point from which fgetc fetches a character be moved without re-opening the file?
Can the number of lines or characters in a file be checked before it is "opened"?
Can I somehow read a line or string from a file and save it to memory without allocating a fixed amount of bytes?
etc
There is no need to open the file more than once, nor to pass through it more than once.
Look at the POSIX getline() function. It reads lines into allocated space. You can use it to read the lines, and then copy the results for your linked list.
There is no need with a linked list to know how many lines there are ahead of time; that's an advantage of lists.
So, the code can be done with a single pass. Even if you can't use getline(), you can use fgets() and monitor whether it reads to end of line each time, and if it doesn't you can allocate (and reallocate) space to hold the line as needed (malloc(), realloc() and eventually free() from <stdlib.h>).
Your specific questions are largely immaterial if you adopt anything of the approach I suggest, but:
Using fseek() (and in extremis rewind()) will move the read pointer (for fgetc() and all other functions), unless the 'file' does not support seeking (eg, a pipe provided as standard input).
Characters can be determined with stat() or fstat() or variants. Lines cannot be determined except by reading the file.
Since the file could be from zero bytes to gigabytes in size, there isn't a sensible way of doing fixed size allocations. You are pretty much forced into dynamic memory allocation with malloc() et al. (Behind the scenes, getline() uses malloc() and realloc().)
You cannot count the number of lines in a file without actually traversing it. You could get the total file size, but that's not whats intended here. The idea of using a linked list of lines is that you operate on the file one line at a time. You do not need to read anything in advance. While you haven't read the whole file, read a line, add it to its own node at the end of the linked list, move to the next line.
Regarding your first question: you can change the position in the file you are reading from with the fseek() function.
There are several ways you could do this. For example, you could have a fixed-size buffer, fill it with bytes from the file, copy lines from the buffer to the list, fill the buffer again and so on.

Prepending Data to a File

There's no way in any operating system I'm aware of for a program to prepend data to a file efficiently.
And yet, this doesn't seem difficult -- the file system can add another extent to a file descriptor if needed.
So the question is, why don't operating systems implement this (rather trivial) operation?
I don't think it's as easy as you suggest. It's true that the file-system could allocate a new block, store the prepended data in it, change the file pointer to point to that block and then chain the rest of the file from that block. Just like adding a node to the front of a linked list, right?
But what happens when (as is probably the case) the prepended data doesn't fill the assigned block. I don't imagine that many filesystems would have a machanism for chaining partial blocks, but even if they do it would result in huge inefficiencies. You'd end up with a file consisting of mostly empty blocks, and you have to have to read and write the entire file to defragment it. Might as well just do the read-and-write operation up front when you're prepending in the first place.
In prepending or appending data to a file, there is always an issue of allocating space. Appending additional space to a file is much easier than prepending because of file descriptors pointing to the beginning of a file's stream. If you want to append to a file, the file descriptor need not be changed, just the size of the file and the allocated memory. If you want to prepend to a file, a new file descriptor must be immediately instantiated, either to write the prepended data to first or to store the location of the data being prepended while the original is updated.
Making a new file descriptor can be tricky, as you must also update any references pointing to it. This is why it is easy for an OS to implement appending data and slightly harder to implement prepending.

Resources