I try to read a file to which my FILE* fp points and I want to know where the end of the file is. Therefore I use fseek(); At the end of the file, I want to write data from my structure data.
void printData(FILE *fp)
{
struct data tmp;
fseek(fp,0,SEEK_END);
while(fread(&tmp,sizeof(struct data),1,fp) > 0)
{
puts("test2");
printf("Vorname: %s\n",tmp.vorname);
printf("Nachname: %s\n",tmp.name);
printf("Adresse: %s\n",tmp.adresse);
}
}
This is how my structure is defined:
struct data
{
char name[30];
char vorname[20];
char adresse[50];
};
My Problem is, that the while loop isn't executed even once. Do I forgot something?
fseek(fp,0,SEEK_END) positions the file pointer at the end of the file (starting point end of the file offset 0), when you then try to read from the file fread of course doesn't read anything.
instead open the file in append mode and fwrite the number of records, these will be appended to the file.
The third variable '1' in fread actually indicates number of items to be read and you are just reading one item. Refer fread document for this:
http://pubs.opengroup.org/onlinepubs/009696899/functions/fread.html
After seeking to the end-of-file you won't be able to read anything. If you just want to know the file size, you can mybe use fstat() instead, or you do the fseek() after reading what you wanted to read, thad depends on what you're trying to achieve.
fread() is used for reading contents from file not for writing.
Use fwrite() for writing contents to file.
Like:
fwrite(&tmp , 1 , sizeof(struct data) , fp );
Read more about:
fread() and fwrite()
You are seeking to the start of the file, since you're setting the offset to 0. That doesn't sound like what you want to be doing, but on the other hand seeking to the end and then trying to read would also fail. I'm confused. :/
Could it be that you meant fwrite(), rather than `fread()? Not likely since the rest of the code prints the results after the I/O, which is logical for reading but not for writing.
It would be helpful with more information, like your file is opened and what it does contain when you run the program.
Related
I want to overwrite an struct in a binary file. Here's my code
:
struct my_st {
char value[10];
};
void replace(char value[10]){
FILE *fpointer;
fpointer = fopen("data.dat", "rb+");
struct my_st x;
struct my_st new;
new.value="test";
while(1) {
fread(&x,sizeof(x),1,fpointer);
if(strcmp(x.value,value)==0)
break;
}
fwrite(&new,sizeof(x),1,fpointer);
}
I even check the place of file position pointer by printing it's value before fwrite and it was correct but it just append new data at the end of file and do not replace.
any suggestions?
If you open a file for update (+) and if you do one or more read operations, you must do a positioning operation (e.g. fseek()) before you do any writes. If you do one or more write operations, you must do a positioning operation (e.g. rewind()) before you do any reads. See POSIX's specification of fopen() for example.
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, the application shall ensure that output is not directly followed by input without an intervening call to fflush() or to a file positioning function (fseek(), fsetpos(), or rewind()), and input is not directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
You are doing no positioning operations between reads and writes. That, in and of itself, leads to undefined behaviour.
Assuming your implementation exhibits 'undefined behaviour' by not going out of its way to misbehave, after your last fread(), you will write over the next entry — or append a new entry if the last one read was at the end of the file.
Decide where you want the data written.
Seek to the correct location (use fseek(fp, 0L, SEEK_CUR) if you don't want to move the read/write pointer).
Write.
If you'll be reading next, do another seek — another no-op if need so be.
This code correctly reads a file line-by-line, stores each line in line[] and prints it.
int beargit_add(const char* filename) {
FILE* findex = fopen(".beargit/.index", "r");
char line[FILENAME_SIZE];
while(fgets(line, sizeof(line), findex)) {
strtok(line, "\n");
fprintf(stdout, "%s\n", line);
}
fclose(findex);
return 0;
}
However, I am baffled as to why using fgets() in the while loop actually reads the file line-by-line. I am brand new to C after having learned Python and Java.
Since each call to fgets() is independent, where is C remembering which line it is currently on each time you call it? I thought it might have to do with changing the value FILE* index points to, but you are passing the pointer into fgets() by value so it could not be modified.
Any help in understanding the magic of C is greatly appreciated!
It's not fgets keep track, findex does this for you
findex is a FILE type, which includes infomation about a open file such as file descriptor, file offset
FILE is a encapsulation of I/O in OS.
more about: FILE
Object type that identifies a stream and contains the information needed to control it, including a pointer to its buffer, its position indicator and all its state indicators.
and the offset is to keep track of the file, each time you read the file, it starts from the offset. All these work are done by FILE, it do for you, and for fgets
more info about offset offset wiki
I thought it might have to do with changing the value FILE* index points to
it's not the value of the pointer itself that is changed. The pointer points to a structure (of type FILE) which contains information about the stream associated with that structure/pointer. Presumably, one of the members of that structure contains a "cursor" that points to the next byte to be read.
Or maybe it's just got a file descriptor int (like on many Unices) and I/O functions just call out to the kernel in order to obtain information about the file descriptor, including the current position.
I have been trying for a long time to figure out how to get the program to read text from a file. I have tried a solution with fgets() and a loop. The program runs but does not print the variable, indicating the text was not extracted.
#include <stdio.h>
#include <string.h>
#include "stdfn.h"
int main(int argc, char* argv[])
{
char* request;
char bf_text[1024];
char character;
intro("Site Blocker", 2014, "MIT");
request = bash("curl http://redsec.ru/blocked_sites.txt"); // Source of bash() is at line 139 https://github.com/Pavelovich/lib-c/blob/master/stdfn.h
//printf("%s", request);
FILE* block_file = fopen(".blocked_sites", "w+"); // Changed from "w" based on this thread, currently only outputs a small part of the file.
FILE* hosts = fopen("hosts", "w");
FILE* hosts_tmp = fopen(".hosts", "w");
// Print the text of the web request to the temporary
// .blocked_sites file
fprintf(block_file, "%s", request);
rewind(block_file);
fread(bf_text, sizeof(block_file), 1, block_file);
printf("%s", bf_text);
fclose(block_file);
return 0;
}
sizeof(block_file) does not give you the size of the file. It'll give you the size of a file pointer, probably either four or eight bytes. Probably eight in your case, since you're saying it's reading "74.125.2", which is eight bytes, and then going haywire. You'll need to use something like stat() on a POSIX system, or a combination of fseek() and ftell().
You should also open files in binary mode if you're going to use fread() or fwrite(), since they are binary file IO functions. It won't make a difference on UNIX systems, but it may well on Windows, for instance. You shouldn't really mix text and binary mode IO functions in the way that you have for this reason.
You should also be checking the returns from your fopen() calls to make sure they succeeded.
And that bash() function you're using is completely broken, too. You'll get a memory leak every time it's called because it never free()s output, and it's making the same sizeof error that you are, although it'll still work because of the loop it's in. It'll just waste all that memory it allocated. And you are leaking memory because you never free(request). And you'd better never #include it in more than one translation unit, either, unless you want multiple definition errors all over the place. That whole "library" is riddled with schoolboy-type errors, in fact, including repeated failures to check the return from malloc(), allocating memory to fit a pointer instead of the thing it's pointing at, and so on.
You are opening block_file for "write only". Try changing the mode parameter to "w+" i.e.
FILE block_file = fopen(".blocked_sites", "w+");
If you want to open an existing file rather than creating a new one each time, use "r+" or "a+" instead of "w+".
Is there a simple way to insert something at the beginning of a text file using file streams? Because the only way I can think of, is to load a file into a buffer, write text-to-append and then write the buffer. I want to know if it is possible to do it without my buffer.
No, its not possible. You'd have to rewrite the file to insert text at the beginning.
EDIT: You could avoid reading the whole file into memory if you used a temporary file ie:
Write the value you want inserted at the beginning of the file
Read X bytes from the old file
Write those X bytes to the new file
Repeat 2,3 until you are done reading the old file
Copy the new file to the old file.
There is no simple way, because the actual operation is not simple. When the file is stored on the disk, there are no empty available bytes before the beginning of the file, so you can't just put data there. There isn't an ideal generic solution to this -- usually, it means copying all of the rest of the data to move it to make room.
Thus, C makes you decide how you want to solve that problem.
Just wanted to counter some of the more absolute claims in here:
There is no way to append data to the beginning of a file.
Incorrect, there are, given certain constraints.
When the file is stored on the disk, there are no empty available bytes before the beginning of the file, so you can't just put data there.
This may be the case when dealing at the abstraction level of files as byte streams. However, file systems most often store files as a sequence of blocks, and some file systems allow a bit more free access at that level.
Linux 4.1+ (XFS) and 4.2+ (XFS, ext4) allows you to insert holes into files using fallocate, given certain offset/length constraints:
Typically, offset and len must be a multiple of the filesystem logical block size, which varies according to the filesystem type and configuration.
Examples on StackExchange sites can be found by web searching for 'fallocate prepend to file'.
There is no way to append data to the beginning of a file.
The questioner also says that the only way they thought of solving the problem was by reading the whole file into memory and writing it out again. Here are other methods.
Write a placeholder of zeros of a known length. You can rewind the file handler and write over this data, so long as you do not exceed the placeholder size.
A simplistic example is writing the size of an unsigned int at the start that represents the count of lines that will follow, but will not be able to fill in until you reached the end and can rewind the file handler and rewrite the correct value.
Note: Some versions of 'C' on different platforms insist you finally place the file handler at the end of file before closing the file handler for this to work correctly.
Write the new data to a new file and then using file streams append the old data to the new file. Delete the old file and then rename the new file as the old file name. Do not use copy, it is a waste of time.
All methods have trade offs of disk size versus memory and CPU usage. It all depends on your application requirements.
Not strictly a solution, but if you're adding a short string to a long file, you can make a looping buffer of the same length you want to add, and sort of roll the extra characters out:
//also serves as the buffer; the null char gives the extra char for the begining
char insRay[] = "[inserted text]";
printf("inserting:%s size of buffer:%ld\n", insRay,sizeof(insRay));
//indecies to read in and out to the file
int iRead = sizeof(insRay)-1;
int iWrite = 0;
//save the input, so we only read once
int in = '\0';
do{
in = fgetc(fp);
//don't go to next char in the file
ungetc(in,fp);
if(in != EOF){
//preserve og file char
insRay[iRead] = in;
//loop
iRead++;
if(iRead == sizeof(insRay))
iRead = 0;
//insert or replace chars
fputc(insRay[iWrite],fp);
//loop
iWrite++;
if(iWrite == sizeof(insRay))
iWrite = 0;
}
}while(in != EOF);
//add buffer to the end of file, - the char that was null before
for(int i = 0; i < sizeof(insRay)-1;i++){
fputc(insRay[iWrite],fp);
iWrite++;
if(iWrite == sizeof(insRay))
iWrite = 0;
}
Can you set any index of array as starting index i.e where to read from file? I was afraid if the buffer might get corrupted in the process.
#include <stdio.h>
int main()
{
FILE *f = fopen("C:\\dummy.txt", "rt");
char lines[30]; //large enough array depending on file size
fpos_t index = 0;
while(fgets(&lines[index], 10, f)) //line limit is 10 characters
{
fgetpos (f, &index );
}
fclose(f);
}
You can, but since your code is trying to read the full contents of the file, you can do that much more directly with fread:
char lines[30];
// Will read as much of the file as can fit into lines:
fread(lines, sizeof(*lines), sizeof(lines) / sizeof(*lines), f);
That said, if you really wanted to read line by line and do it safely, you should change your fgets line to:
// As long as index < sizeof(lines), guaranteed not to overflow buffer
fgets(&lines[index], sizeof(lines) - index, f);
Not like this no. There is a function called fseek that will take you to a different location in the file.
Your code will read the file into a different part of the buffer (rather than reading a different part of the file).
lines[index] is the index'th character of the array lines. Its address is not the index'th line.
If you want to skip to a particular line, say 5, then in order to read the 5th line, read 4 lines and do nothing with them, them read the next line and do something with it.
If you need to skip to a particular BYTE within a file, then what you want to use is fseek().
Also: be careful that the number of bytes that you tell fgets to read for you (10) is the same as the size of the array you are putting the line into (30) - so this is not the case right now.
If you need to read a part of a line starting from a certain character within that line, you still need to read the whole line, then just choose to use a chunk of it starting someplace other than the beginning.
Both of these examples are like requesting a part of a document from a website or a library - they're not going to tear out a page for you, you get the whole document, and you have to flip to what you want.