C: One pointer for reading and one pointer for updating the same file - c

I need to build a program that reads each record, and according to that record information would update some other records on the same file. For that, I was thinking in this approach:
int main(int argc, char *argv[]) {
FILE *my_file;
int files_read;
struct my_struct an_struct;
my_file = fopen("myfile.dat", "rb");
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("main->files_read: %d \n", files_read); //This prints one
while (files_read == 1) {
do_update();
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("main->files_read: %d \n", files_read); //This prints one
}
fclose(archivo_paises);
return 0;
}
In the main function I'm reading the contents of the file, and every time I call read I get one as a response until I reach the end of the file. The problem is in the do_update function:
void do_update() {
FILE *my_file;
int files_read;
struct my_struct an_struct;
struct my_struct another_struct;
my_files = fopen("myfile.dat", "wb+"); //Using rb+ solves it
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("do_update->files_read: %d \n", files_read);
//This printed zero!. Prints one using rb+
while (files_read == 1) { //This never gets executed. Unless you use rb+
if(something){
fwrite(&another_struct, sizeof(struct my_struct), 1, my_file);
// Using rb+, this returns zero and didn't update
}
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("do_update->files_read: %d \n", files_read);
}
fclose(my_file);
}
What's happening is that the files_read variable gets the value of zero after the read call, so the logic to update the file is never executed.
Why is read returning zero when opening a file for wb+?
Update:
Using rb+ as file mode on do_update() works, but now the call to fwrite() always returns zero, and it didn't update the file. Is is related to the mode?

fwrite is moving the position in the file to the end of the file. The fread then has nothing to read.
Use fgetpos to save the file position before the fwrite, and fsetpos to set the position back after the fwrite.

The meaning of the flag "w+" (from http://www.cplusplus.com/reference/cstdio/fopen/):
write/update: Create an empty file and open it for update (both for input and output). If a file with the same name already exists its contents are discarded and the file is treated as a new empty file.
When you open a file with "w+", you will need to write to it first before you can read from it.
Update
Example program to demonstrate use of "rb+".
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void createFile(char const* filename, int num)
{
int i = 0;
int data = 0;
FILE* out = fopen(filename, "wb");
if ( out == NULL )
{
return;
}
for (i = 0; i < num; ++i )
{
data = rand()/10000;
fwrite(&data, sizeof(data), 1, out);
}
fclose(out);
}
void displayFileContents(char const* filename, int num)
{
int i = 0;
int data = 0;
FILE* in = fopen(filename, "rb");
if ( in == NULL )
{
return;
}
for (i = 0; i < num; ++i )
{
fread(&data, sizeof(data), 1, in);
printf("%d\n", data);
}
fclose(in);
}
void testReadAndWrite(char const* filename, int num)
{
int i = 0;
int data = 0;
long int pos = 0;
FILE* in = fopen(filename, "rb+");
if ( in == NULL )
{
return;
}
for ( i = 0; i < num; ++i )
{
pos = ftell(in);
fread(&data, sizeof(data), 1, in);
printf("%d\n", data);
// Rewind to previos position.
fseek(in, pos, SEEK_SET);
// Write at the previus position.
data = rand();
printf("%d\n", data);
if ( fwrite(&data, sizeof(data), 1, in) != 1 )
{
printf("Unable to write using fwrite.\n");
}
// Rewind to previos position.
fseek(in, pos, SEEK_SET);
// Read from the previus position.
if ( fread(&data, sizeof(data), 1, in) != 1 )
{
printf("Unable to read using fread.\n");
}
printf("%d\n\n", data);
}
fclose(in);
}
int main()
{
char const* filename = "test.txt";
int num = 10;
// See the random number generator.
srand(time(NULL));
// Create a file with some random data.
createFile(filename, num);
// Display the contents of the file.
displayFileContents(filename, num);
printf("\n");
// Test read and write using a single FILE*
testReadAndWrite(filename, num);
}
Sample output:
51830
169074
141071
61921
145333
101195
139074
9535
164668
49552
51830
1030292590
1030292590
169074
1003635396
1003635396
141071
1060541073
1060541073
61921
474399692
474399692
145333
1467401071
1467401071
101195
830521014
830521014
139074
1186142943
1186142943
9535
1759682963
1759682963
164668
848798825
848798825
49552
60932215
60932215

Related

Understanding fseek() in C

I was learing File I/O in C and was interested in using it to read and write structures to files via fwrite() and fread() functions, now after my code ran successfully I was wondering if I could read a specific structure from an array of structures and put it in some given structure.
Here is my attempt at it
#include <stdio.h>
#include <stdlib.h>
typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;
void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}
int main() {
FILE * fp;
fp = fopen("file.txt", "rb+");
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i < 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = 'a';
a[i].toolname[1] = '\0';
a[i].quantity = 0;
a[i].recordno = i + 1;
}
for (int i = 0; i < 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when\
it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]
recordprinter(a[3]);
// this gives output 26 and not 51
return 0;
}
Now when I ran the programm I expected 51 a 0 0.00000 as output,
but to my surprise it is picking up the 26th structure and putting it in a[3]
Any help will be appritiated!!
Try changing fopen to use w+ instead of rb+
Also, remove the fseek when creating the file, as mentioned, fwrite definitely advances the file offset after writing data (provided fwrite does write data at all).
Here is the output observed using the modified code below.
gcc main.c
./a.out
51 a 0 0.000000
// main.c
#include <stdio.h>
#include <stdlib.h>
typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;
void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}
int main() {
FILE * fp;
// recommend for this example using w+
// w because it creates the file if the file doesn't exist
// r fails if the file doesn't exist (and that doesn't seem useful here)
// + because you are reading and writing
// avoiding b and choosing POSIX - linux
// may be wrong, if libc docs says b is needed then use b
// my doc "man fopen" says b is ignored
fp = fopen("file.txt", "w+");
// check return values, file pointer exist? fail if not
if (fp==NULL) { printf( "oops file not opened\n" ); return 1; }
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i < 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = 'a';
a[i].toolname[1] = '\0';
a[i].quantity = 0;
a[i].recordno = i + 1;
}
// alternative way to save 100 objects
// if ( fwrite(a, sizeof(tools), 100, fp) != 100 )
// {
// printf( "oops 100 objects not written to file\n" );
// return 1;
// }
for (int i = 0; i < 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
// remove fseek, not needed, fwrite does what is needed here
//fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when
// it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
// no review after this line, it seems to do what author intends
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]
recordprinter(a[3]);
// this gives output 51 as desired
return 0;
}

How to read the content from the second line onwards on a .txt file on C

I need help to read the numbers of a .txt file and put them in an array. But only from the second line onwards. I'm stuck and don't know where to go from the code that i built.
Example of the .txt file:
10 20
45000000
48000000
56000000
#define MAX 50
int main (void){
FILE *file;
int primNum;
int secNum;
int listOfNumers[50];
int numberOfLines = MAX;
int i = 0;
file = fopen("file.txt", "rt");
if (file == NULL)
{
printf("Error\n");
return 1;
}
fscanf(file, "%d %d\n", &primNum, &secNum);
printf("\n1st Number: %d",primNum);
printf("\n2nd Number: %d",secNum);
printf("List of Numbers");
for(i=0;i<numberOfLines;i++){
//Count the number from the second line onwards
}
fclose(file);
return 0;
}
You just need a loop to keep reading ints from file and populate the listOfNumers array until reading an int fails.
Since you don't know how many ints there are in the file, you could also allocate the memory dynamically. Example:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE* file = fopen("file.txt", "rt");
if(file == NULL) {
perror("file.txt");
return 1;
}
int primNum;
int secNum;
if(fscanf(file, "%d %d", &primNum, &secNum) != 2) {
fprintf(stderr, "failed reading primNum and secNum\n");
return 1;
}
unsigned numberOfLines = 0;
// allocate space for one `int`
int* listOfNumers = malloc((numberOfLines + 1) * sizeof *listOfNumers);
// the above could just be:
// int* listOfNumers = malloc(sizeof *listOfNumers);
while(fscanf(file, "%d", listOfNumers + numberOfLines) == 1) {
++numberOfLines;
// increase the allocated space by the sizeof 1 int
int* np = realloc(listOfNumers, (numberOfLines + 1) * sizeof *np);
if(np == NULL) break; // if allocating more space failed, break out
listOfNumers = np; // save the new pointer
}
fclose(file);
puts("List of Numbers:");
for(unsigned i = 0; i < numberOfLines; ++i) {
printf("%d\n", listOfNumers[i]);
}
free(listOfNumers); // free the dynamically allocated space
}
There are a few ways to approach this; if you know the size of the first line, you should be able to use fseek to move the position of the file than use getline to get each line of the file:
int fseek(FILE *stream, long offset, int whence);
The whence parameter can be:
SEEK_SET : the Beginning
SEEK_CUR : the current position
SEEK_END : the End
The other option would to encapsulate the entire file read in a while loop:
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
int counter = 0;
while((linelen = getline(&line, &linecap, file)) != -1){
if counter == 0{
sscanf(line, "%d %d\n", &primNum, &secNum);
}else{
//Process your line
}
counter++; //This would give you your total line length
}

i am trying to read the values stored inside the buffer but instead its showing me the address?

i want to print the values in the location not the address..
when i run the program using breakpoint it does increases the values but doesn't print the values contained in the addresses..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "conio.h"
int main()
{
char ch;
char buffer[100];
char* p;
p = buffer;
FILE *fp;
fp = fopen("D:\\Telenor_Short_01.vts","rb");// binary mode
fseek(fp,0,SEEK_END); //sets the file position of the stream to the given offset
int size=ftell(fp); //returns the current file position of the given stream.
printf("size of file is :%d\n",size);
if( fp == NULL ) //error checking
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
fread(p,1,100,fp);
for (int i=0;i<100;i++)
{
printf("%04x\n",*p);
p++;
}
fclose(fp);
/*printf("The contents of %s file are :\n", file_name);*/
/*int i;
while( ( ch = fgetc(fp) ) != EOF )
{
printf("%02X ",ch);
if( !(++i % 16) ) putc('\n', stdout);
}
fclose(fp);
putc('\n', stdout);*/
_getch();
return 0;
}
this is the output:
size of file is :185153907
5bf894
5bf895
5bf896
5bf897
5bf898
5bf899
5bf89a
5bf89b
5bf89c
5bf89d
5bf89e
5bf89f
5bf8a0
5bf8a1
5bf8a2
5bf8a3
5bf8a4
5bf8a5
5bf8a6
5bf8a7
5bf8a8
5bf8a9
5bf8aa
5bf8ab
5bf8ac
5bf8ad
5bf8ae
5bf8af
5bf8b0
5bf8b1
5bf8b2
5bf8b3
5bf8b4
5bf8b5
5bf8b6
5bf8b7
5bf8b8
5bf8b9
5bf8ba
5bf8bb
5bf8bc
5bf8bd
5bf8be
5bf8bf
5bf8c0
5bf8c1
5bf8c2
5bf8c3
5bf8c4
5bf8c5
5bf8c6
5bf8c7
5bf8c8
5bf8c9
5bf8ca
5bf8cb
5bf8cc
5bf8cd
5bf8ce
5bf8cf
5bf8d0
5bf8d1
5bf8d2
5bf8d3
5bf8d4
5bf8d5
5bf8d6
5bf8d7
5bf8d8
5bf8d9
5bf8da
5bf8db
5bf8dc
5bf8dd
5bf8de
5bf8df
5bf8e0
5bf8e1
5bf8e2
5bf8e3
5bf8e4
5bf8e5
5bf8e6
5bf8e7
5bf8e8
5bf8e9
5bf8ea
5bf8eb
5bf8ec
5bf8ed
5bf8ee
5bf8ef
5bf8f0
5bf8f1
5bf8f2
5bf8f3
5bf8f4
5bf8f5
5bf8f6
5bf8f7
but i want the values ..
First, check fp for NULL immediately after fopen. Second seek to the beginning of the file before fread. Last, most importantly, check the return value of fread, because that's the number of elements that was read into the buffer. It may be smaller than the buffer.
fp = fopen("D:\\Telenor_Short_01.vts","rb");// binary mode
if( fp == NULL ) //error checking
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
fseek(fp,0,SEEK_END); //sets the file position of the stream to the given offset
int size=ftell(fp); //returns the current file position of the given stream.
printf("size of file is :%d\n",size);
fseek(fp, 0, SEEK_SET);
int nread = fread(p, 1, 100, fp);
for (int i=0; i<nread; i++)
{
printf("%04x\n", *p);
p++;
}
fclose(fp);
In addition, in C, you can access array elements either by subscription or by pointers arithmetic, the two are the same effect:
char arr[8];
arr[3] is same as *(arr + 3);
&arr[3] is same as arr + 3;
To read the big file by chunks:
fseek(fp, 0, SEEK_SET);
char buf[4096];
int nread;
int i;
while (1) {
nread = fread(buf, 1, 4096, fp);
for (i=0; i<nread; i++)
{
printf("%02x\n", buf[i]);
}
if (nread < 4096)
break;
}
fclose(fp);

Read a file containing an array of long in C

I am trying to get the data from an array of longs that I have just created but I got different data.
please see code below :
#include <string.h>
#include "readfile.h"
int main()
{
long wr_data [6] ;
wr_data[0] = 11;
wr_data[1] = 1100;
wr_data[2] = 1122323;
wr_data[3] = 11333;
wr_data[4] = 11434243;
wr_data[5] = 1166587;
writeFile(wr_data);
readFile();
return(0);
}
int readFile()
{
FILE *file;
long * data
printf("Error Reading File\n");;
/* Open file for both reading and writing */
file = fopen(fileName, "r");
if (file == NULL)
{
printf("Error Reading File\n");
return -1;
}
for (int i = 0; i < 5; i++)
{
fscanf(file, "%ld", &data[i] );
printf("data[%d]: %ld \n",i, data[i]);
}
fclose(file);
return 0;
}
int writeFile(long * data)
{
FILE *fp;
if (data != NULL)
{
if ((fp = fopen(fileName,"w")) == NULL)
return -1;
if (*data !=0 )
fwrite(data,sizeof(long),6,fp);
printf("Write data\n");
fclose(fp);
}
return 0;
}
the result I get is as follows :
Write data
data[0]: 140526045102081
data[1]: 47
data[2]: 197764
data[3]: 140526045102080
data[4]: 4096
I want to preserve the write function as it is as it comes from an existing code. I tried also the function fread but without success
fread(data, sizeof(long ), 6, file);
Thanks in advance for help.
It's working here. I made the following changes to your code:
//needed for malloc
#include <stdio.h>
//needed for output
#include <stdlib.h>
...
char *fileName = "so";
...
//allocate memory to store the values
long *data = (long *)malloc(sizeof(long)*6);
...
//read the stored longs
fread(data, sizeof(long ), 6, file);
int i;
for(i=0; i<6; i++)
printf("%ld\n", data[i]);
what do you think?
edit:
Well the main change was the memory allocation. When you want to store values of any kind, your program needs to be granted by the operating system a memory zone to store those values.
In this case we had two options, either create a staticly allocated array with a fixed size, or allocate the needed memory in a dynamic fashion with the malloc function or equivalent.
Don't forget, if you want to store something, first make sure you have a place for it to be stored (i.e. allocated memory). If you don't you will most likely get an error "Segmentation Fault" aka "SIGSEGV" which means that you tried to access memory that didn't belong to you.
Also, the "fscanf(file, "%ld", &data[i] );" will read "file" as text and will try to parse floats out of that same text. Since you're storing the longs as longs and not as text, this will not work, since you're writing and reading different things.
You are writing the binary content of the array to the file and afterwards try to interpret this as a long value which can obviously not work. If you want to store the numbers as text you must convert them to text before writing or print them to file by using the fprintf(FILE *, const char *, ...) function.
It is working as expected using the following code using a text file (you might want to change the filename). Otherwise you could just fwrite and fread the whole content, depending on your needs.
#include <stdio.h>
const char *filename = "yourfile";
int readFile()
{
FILE *file;
long data[6];
int i;
printf("Error Reading File\n");;
/* Open file for both reading and writing */
file = fopen(filename, "r");
if (file == NULL)
{
printf("Error Reading File\n");
return -1;
}
for (i = 0; i < 6; i++)
{
fscanf(file, "%ld", &data[i] );
printf("data[%d]: %ld \n",i, data[i]);
}
fclose(file);
return 0;
}
int writeFile(long * data)
{
FILE *fp;
int i;
if (data != NULL)
{
if ((fp = fopen(filename,"w")) == NULL)
return -1;
if (*data !=0 )
{
for(i = 0; i != 6; ++i)
fprintf(fp, "%ld ", data[i]);
}
printf("Write data\n");
fclose(fp);
}
return 0;
}
int main()
{
long wr_data [6] ;
wr_data[0] = 11;
wr_data[1] = 1100;
wr_data[2] = 1122323;
wr_data[3] = 11333;
wr_data[4] = 11434243;
wr_data[5] = 1166587;
writeFile(wr_data);
readFile();
return(0);
}

c code text not displayed

iv'e written a part of a code which basically transfers text from a txt file into a variable and prints it(as a part of a program),yet it does not print the contents at all.
#include <stdio.h>
#include <stdlib.h>
#define WRONG_ARGUMENTS (-1)
int Lines(FILE * file);
int Length(FILE * file);
int Read(FILE * file);
int Lines(FILE * file)
{
int c=0,count=0;
++count;
while(c!=EOF)
{
c=fgetc(file);
if(c=='\n')
++count;
}
return count;
}
int Length(FILE * file)
{
int c,count=0;
while((c=fgetc(file))!=EOF)
{
++count;
}
return count;
}
int Reader(FILE * Text,char * File)
{
int counter=0;
while(fscanf(Text,"%s",File)!=EOF)
{
++counter;
strcat(File," ");
}
return counter;
}
int main(int argc,char * argv[]) {
FILE * Text=NULL;
if(argc!=2)
{
printf("usage:library text dictionary\n");
return -1;
}
Text = fopen(argv[1],"r");
if(Text==NULL)
{
printf("file %s could not be opened\n",argv[1]);
return -1;
}
char * File = "";
File=malloc(Length(Text)*(sizeof(char)));
int r = Reader(Text,File);
printf(File);
return 0;
}
i will be more than glad to understand the problem in the partial code
the output is x>
thanks,
Consider the following cut-down example. You'll notice that the getFileLength function (a) doesn't actually read anything from the file and (b) makes use of the fseek and ftell functions - fseek is the function that you use to reposition the file-pointer when it reaches EOF.
Imagine that you weren't printing the data, but doing something else with it. What if the file is a billion bytes long? We sure don't want to read 1,000,000,000 times from it just to determine its length!
As for the use of calloc - it zero initializes the data it allocates. Since you're reading text, you want to ensure that the text is NULL-terminated. (NULL generally = 0, though I've seen evil macros that change this) This NULL terminator is also why I allocate 1 byte more than the file contains.
#include <stdio.h>
#include <stdlib.h>
long getFileLength(FILE *input)
{
long result;
long origPos = ftell(input);
fseek(input, 0, SEEK_END);
result = ftell(input);
fseek(input, origPos, SEEK_SET);
return result;
}
int main (void)
{
FILE *fp;
long fileLen, numBytesRead;
char *data;
fp = fopen("main.cpp", "rb");
fileLen = getFileLength(fp);
data = (char*)calloc(sizeof(char), fileLen+1);
numBytesRead = fread(data, sizeof(char), fileLen, fp);
if (numBytesRead != fileLen)
printf("Error reading all bytes from file. Expected: %d, Read %d\n", fileLen, numBytesRead);
else
printf("%s", data);
free(data);
fclose(fp);
}

Resources