Loop through the file and read all records - c

I've got a file with multiple records. Each record contains a type(a binary value number), len(bin value again), and data(binary value whose length is len). The file contains multiple records. I want to print every record which contains it's own type, len, and data.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
typedef struct file_s {
int16_t type;
int32_t length;
// Assumption: Each record is 16 bits
// For a record size of 32 bits, use int32_t*
int16_t* data;
} file_s;
int main() {
file_s file;
FILE* f = fopen("file.bin","r");
if (f == NULL) {
perror("Error");
return 1;
}
fread(&file.type, sizeof(file.type), 1, f);
fread(&file.length, sizeof(file.length), 1, f);
file.data = malloc(file.length * sizeof(*file.data));
fread(file.data, sizeof(*file.data), file.length, f);
fclose(f);
// Process the data
/* ... */
free(file.data);
return 0;
}
How do I loop through the file and print each record.

The idea is to check the return value of fread every time, if the return value is smaller than expect, then check feof() to see if the end of the file reached. You can check the man page, by google "man fread" and "man feof". You can use a do while loop to loop through the file.
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int feof(FILE *stream);
something like:
while(1) {
size_read = fread(&file.type, sizeof(file.type), 1, f);
if(size_read!=1 || feof(f))
break;
fread(&file.length, sizeof(file.length), 1, f);
//do the same check
file.data = malloc(file.length * sizeof(*file.data));
fread(file.data, sizeof(*file.data), file.length, f);
//do the same check, remember to free the memory!
}

Related

How to read multiple lines at a time from txt file in C?

I am processing *.fastq.gz file, something like the below:
#NB501139:187:H2Y5LBGXB:1:11101:17094:1060 2:N:0:CTTTGCGG
AGAGGATCCGTGTGANANNNGANNNCNNCCGNCTNNTANNAGATCACTTAGNNANNNNACAGCAGAAAANNNNNNNNNACAAGGTTGAAANTNTNTNN
+
A/AA///E/////EE#A###//###A##EEE#AE##EA##EE//<AE<EE<##/####/EE</EAE<//#########/E///</EE<<<#E#A#E##
#NB501139:187:H2Y5LBGXB:1:11101:3442:1060 2:N:0:CTTTGCGG
ACTGAGTCACGCACCNANNNCCNNNCNGCCGNCANNGCNNTGCACCGGTGGNCTNNNNTGTGTACTGAGNNTNNNNNNCATGCACACAGANTNCTCNN
+
AAAAAEEEEE/EEE6#<###EE###E#EEE/#AE##<E##EEEEEE/EEEA#EE####EAEEEEEEE/<##A######EEE/E<E/EEE/#A#AEA##
The file could be larger than RAM, so I process it block by block using file streaming, then output the result. By block, I mean 4 lines are a block.
#include <stdio.h>
#include <zlib.h>
#define MAX_LINE_LENGTH 128
typedef struct fastq
{
char *id;
char *seq;
char *qual;
} fastq;
fastq *get_fastq(gzFile file)
{
fastq *out = (fastq *)malloc(sizeof(fastq));
out->id = (char *)malloc(MAX_LINE_LENGTH);
out->seq = (char *)malloc(MAX_LINE_LENGTH);
out->qual = (char *)malloc(MAX_LINE_LENGTH);
char temp[MAX_LINE_LENGTH];
if (gzgets(file, out->id, MAX_LINE_LENGTH) != NULL)
{
gzgets(file, out->seq, MAX_LINE_LENGTH);
gzgets(file, temp, MAX_LINE_LENGTH);
gzgets(file, out->qual, MAX_LINE_LENGTH);
}
else
{
free_fastq(out);
return NULL;
}
return out;
}
To limit the I/O calling, I am looking for a way to read 4 lines at a time rather than calling gzgets() 4 times for one block. I'm unsure if this will save time; any suggestion is welcome.

C file Fwrite and fread struct pointers

The program only works for the first time. What was supposed to happen the second time was to add the same data to the binary file but that doesn't happen.
First run: It runs normal and it shows that it writed to the file.
Secound run: It writes to the file but doesnt read.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name, *role, *course;
int year, id;
} StudentFile;
void saveBin(StudentFile *studentsFile, int lines){
FILE *file = fopen("studentsx.bin","ab");
if (!file) {
printf("\n\n\tImposible to open file. \n\n");
exit(1);
}
for (int i = 0; i < lines; i++){
fwrite(&studentsFile[i], sizeof(StudentFile), 1, file);
}
fclose(file);
}
void readBin(){
StudentFile *studentsFile = malloc(sizeof(StudentFile)*5000);
FILE *file = fopen("studentsx.bin","rb");
if (!file) {
printf("\n\n\tImposible to open file. \n\n");
exit(1);
}
int j = 0;
while (fread(&studentsFile[j], sizeof(StudentFile), 1, file)){
printf("\nLine read %d: %s\t%s\t%d\t%d\t%s", j+1, studentsFile[j].name, studentsFile[j].role, studentsFile[j].year, studentsFile[j].id, studentsFile[j].course);
j++;
}
fclose(file);
}
void main(){
StudentFile *studentsFile = malloc(sizeof(StudentFile)*2);
int lines = 0;
studentsFile[0].name = "John";
studentsFile[0].role = "Gamer";
studentsFile[0].year = 1999;
studentsFile[0].id = 1;
studentsFile[0].course = "IOT";
studentsFile[1].name = "Piter";
studentsFile[1].role = "GamerXL";
studentsFile[1].year = 1991;
studentsFile[1].id = 2;
studentsFile[1].course = "IOTXL";
lines = 2;
saveBin(studentsFile, lines);
readBin();
}
You are writing pointers, not strings. fwrite writes single contiguous array of memory. In your case the StudentFiles and actual strings are scattered all over the static memory and heap memory.
Consider your struct:
typedef struct {
char *name, *role, *course;
int year, id;
} StudentFile;
it looks something like this in memory:
[<pointer to name><pointer to role><pointer to course><year><id>]
somewhere else in a different block of memory:
[John\0Gamer\0\OIT\o.......]
You wrote the first block above and left out the second one.
There are multiple approaches to this problem and we usually name them "serialization" - take your complex data structure and serialize it into a linear file.
One of the approaches is to allocate fixed size block within your structure StudentFile:
#define MAX_NAME 100
#define MAX_ROLE 100
#define MAX_COURSE 100
typedef struct {
char name[MAX_NAME];
char role[MAX_ROLE];
char course[MAX_COURSE];
int year, id;
} StudentFile;
then strings name, role and course will be inside of StudentFile:
[<100 bytes for name><100 bytes for role><100 bytes for course><year><id>]
this is contiguous block of memory and if can be written using single call to fwrite like you did.
But you won't be able to assign strings like you did with
studentsFile[i].name = "John";
C has strncpy for that:
strcpy(studentsFile[0].name, "John", MAX_NAME);
Another approach is to have several calls to fwrite. For every string, you write length first, then the string itself. For primitive types like int you just write that int.
First you gather strings from different locations pointed by the pointers:
size_t nameLen = strlen(studentsFile[i].name) + 1;/* +1 for the final zero*/
fwrite(&nameLen, sizeof(size_t), 1, file);
fwrite(studentsFile[i].name, nameLen, 1, file);
size_t roleLen = strlen(studentsFile[i].role) + 1;
fwrite(&roleLen, sizeof(size_t), 1, file);
fwrite(studentsFile[i].role, roleLen, 1, file);
size_t courseLen = strlen(studentsFile[i].course) + 1;
fwrite(&courseLen, sizeof(size_t), 1, file);
fwrite(studentsFile[i].course, courseLen, 1, file);
Then you write primitive types:
fwrite(&studentsFile[i].year, sizeof(int), 1, file);
fwrite(&studentsFile[i].id, sizeof(int), 1, file);
Next time when you read the file, you rely on the order of writes and read the fields back in the same order:
size_t nameLen;
fread(&nameLen, sizeof(size_t), 1, file);
char *name = malloc(nameLen);
fread(name, nameLen, 1, file);
size_t roleLen;
fread(&roleLen, sizeof(size_t), 1, file);
char *role = malloc(roleLen);
fread(role, roleLen, 1, file);
size_t courseLen;
fread(&courseLen, sizeof(size_t), 1, file);
char *course = malloc(courseLen);
fread(course, courseLen, 1, file);
int year;
fread(&year, sizeof(int), 1, file);
int id;
fread(&id, sizeof(int), 1, file);
printf("\nLine read %d: %s\t%s\t%d\t%d\t%s", j+1, name, role, year, id, course);
The problem lies somewhere else: Think carefully, what is your code doing with fwrite() here?
typedef struct {
char *name, *role, *course;
int year, id;
} StudentFile;
fwrite(&studentsFile[i], sizeof(StudentFile), 1, file);
What does the file content look like after writing a single element from studentFile?
Three strings and two integers (in their binary form)
Three pointers to somewhere and two integers (all in their binary forms)

c - writing data to wav file

I'm working on an small tool that reads data from an wav file. This tool first extracts the header followed by separating the audio data into left and right channel. Audio files are just files with a sampling frequency of 44100Hz, 16Bit PCM and dual-channel.
After manipulating the data I want to write back the data to an output file and append 100 zeros on each channel. Here the problem occurs: first just half of the desired samples are append on each channel. Secondly the first half of the appended 'zeros' are random data.
See my code below
#include <stdlib.h>
#include <stdio.h>
#define BUFFSIZE 1024
#define NUM_ZEROS 100
#include <stdio.h>
#include <stdlib.h>
typedef struct header_file
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
char subchunk2_id[4];
int subchunk2_size;
} header;
typedef struct header_file* header_p;
int main(int argc, char** argv){
if( argc != 3 ){
printf("Wrong number of input arguments. Aborting.\n");
return -1;
}
char *inputFile = argv[1];
char *outputFile = argv[2];
FILE * infile = fopen(inputFile, "r+");
FILE * outfile = fopen(outputFile, "w+");
int count = 0; // For counting number of frames in wave file.
short int buff16[2*BUFFSIZE]; // short int used for 16 bit as input data format is 16 bit PCM audio
short int buffLeft[BUFFSIZE], buffRight[BUFFSIZE];
header_p meta = (header_p)malloc(sizeof(header)); // header_p points to a header struct that contains the wave file metadata fields
int nb, cnt; // variable storing number of bytes returned
printf("Buffers initialized.\n");
if (infile)
{
fread(meta, 1, sizeof(header), infile);
meta->subchunk2_size = meta->subchunk2_size + 2 * NUM_ZEROS;
fwrite(meta,1, sizeof(*meta), outfile);
while (!feof(infile))
{
nb = fread(buff16,1,BUFFSIZE,infile); // Reading data in chunks of BUFSIZE
count++; // Incrementing Number of frames
for(cnt = 0; cnt < nb/2; cnt++){
buffLeft[cnt] = buff16[2*cnt];
buffRight[cnt] = buff16[2*cnt+1];
}
/*
* TODO: INSERT SIGNAL PROCESSING PART
*/
for(cnt = 0; cnt < nb/2; cnt++){
buff16[2*cnt] = buffLeft[cnt];
buff16[2*cnt+1] = buffRight[cnt];
}
fwrite(buff16,1,nb,outfile);
}
for(cnt = 0; cnt < 2*NUM_ZEROS; cnt++){
buff16[cnt] = 0;
}
fwrite(buff16,1, 2*NUM_ZEROS,outfile);
printf("Number of frames in the input wave file are %d.\n", count);
}
fclose(infile);
fclose(outfile);
return 0;
}
Does somebody have an idea what I did wrong?
Are you sure that only a part of the added zeros is garbage?
You mess up the data size for fread and fwrite
Your buffers are short int:
short int buff16[2*BUFFSIZE]; // BUFFSIZE*2*sizeof(short) bytes
You read only 1/4 of that size:
nb = fread(buff16,1,BUFFSIZE,infile); // BUFFSIZE bytes
This reads BUFSIZE bytes as you only specify a size of 1 per element.
Instead of BUFFSIZE*2 shorts you only read BUFFSIZE bytes.
The return value is number of read elements, i.e. bytes again.
In your buffer that amount of data is only sufficient for nb/2 elements but you access buff16[0] .. buff16[nb-1] where second half of it was not read from the file.
Luckily you also do not write the second half back into the new file as the
same error with length is also present there.
And finally the same problem is present when you append the zero values to the file.
tl;dr
Change your size parameter for fread and fwrite to sizeof(short int).
You have
#define NUM_ZEROS 100
and
fwrite(buff16,1, 2*NUM_ZEROS,outfile);
Aim:
I want to write back the data to an output file and append 100 zeros
on each channel.
I think it should be 100 SAMPLES at each channel.
As you have 16bit PCM each sample is 2 bytes.
So one channel needs 200 bytes (zeros) to be written. Stereo means 400 bytes.
Your fwrite saves just 2*NUM_ZEROS so 200 bytes - this is answer to part about missing samples.
Additionally you declare
short int buff16[2*BUFFSIZE];
while reading just half of it and using half of half (nb/2) for processing. Than write full buffer (actually half of declared) with upper half full of random garbage from memory.

Many doubts about decrypt an image file in c

Firstly, i'm not very familiarized with C, i come from Java, C#, C++... and possibly i inherited defects from this languages in order to realize this practice, well i have the follows question, here is my code:
#include <stdio.h>
#include <stdlib.h>
void decrypt(unsigned long* v, unsigned long* k);
const int MAX = 32;
const long delta = 0x9e3779b9;
long sum=0xC6EF3720;
int main() {
FILE *fp;
FILE *destino;
unsigned long v[2];
unsigned long k[4] = { 128, 129, 130, 131 };
unsigned long tam=0;
char* buffer;
char* aux[sizeof(unsigned long)];
int i;
if ((fp = fopen("image.png", "rb")) == NULL) {
printf ("Error! \n ");
return 0;
}
else {
fread(&aux,sizeof(unsigned long),1,fp);
memcpy(&tam,&aux,sizeof(unsigned long));
buffer = (char*)malloc(tam);
//fread(&buffer,1,tam,fp);
char *buffer2[28568];
fread(&buffer2,1,28568,fp);
/*for(i = 0;i < tam;++i) {
printf("%c", ((char *)buffer2)[i]);
}*/
for(i=4;i<tam;i+=8) {
memcpy(&v,&buffer2[i],8);
decrypt(&v,&k);
}
if ((result= fopen("image2.png", "rb")) == NULL) {
printf ("Error! \n ");
return 0;
}
else {
fwrite(v,sizeof(unsigned long)*2,1,result);
fclose (result);
fclose(fp);
}
}
return 0;
}
void decrypt(unsigned long* v, unsigned long* k) {
int i=0;
while(i<MAX) {
v[1] = v[1] -((4 << v[0])+(k[2]^v[0])+(sum^(5 >> v[0]))+k[3]);
v[0] = v[0] -((4 << v[1])+(k[0]^v[1])+(sum^(5 >> v[1]))+k[1]);
sum = sum-delta;
i++;
}
}
Where tam is the size of my binary file (image in this case) where i store first 4 bytes (unsigned long) where is located the size in my png file (28568)
When i create my char* buffer i have to assign dynamically with malloc but when i make a new fread from my file i get a "No source available for "msvrct!memcpy() at 0xrandom_memory_address" from Eclipse when i debug, well, i comment this line and i try to make it manually set a new buffer2 with 28568 as size of my array, apparently works, making a iteration of buffer2 prints ascii characters values but when i call decrypt for make the decryption of my image, the final result is stored in v array which i have to copy in a new file, i tried to search how to make a empty image png in C but i didn't find anything, so i created a copy of my encrypt image calling it "image2.png" but i suppose this not the "clean solution" for that, because for the other hand is not working at all.
For more explanation about this exercise just say that the decrypt funcion work with blocks of 8 bytes (64 bits) that through a key (array k) make a series of operation where they store in v array itself, crossing through the loop 8 in 8 and retrieve the value of buffer in v in each one, after the loop execution we have the result in v and only left to copy in a new file where finally show up the image decrypt.
It's a very complex practice for all of one newbies in C, it's driving my crazy trying to figure out what i doing wrong.
I hope anyone can see what i'm not able to for now.
I think you are having problems with the declarations of the buffers. I think the correct should be:
FILE *fp;
FILE *destino;
unsigned long v[2];
unsigned long k[4] = { 128, 129, 130, 131 };
unsigned long tam=0;
char* buffer;
char aux[sizeof(unsigned long)]; // without the "*"
int i;
if ((fp = fopen("image.png", "rb")) == NULL) {
printf ("Error! \n ");
return 0;
}
else {
fread(aux,sizeof(unsigned long),1,fp);
memcpy(&tam,aux,sizeof(unsigned long));
buffer = (char*)malloc(tam);
//fread(buffer,1,tam,fp); // without the "&" in this case
char buffer2[28568]; // without the "*"
fread(buffer2,1,28568,fp); // or fread(buffer,1,tam,fp);
/*for(i = 0;i < tam;++i) {
printf("%c", buffer2[i]); // or buufer[i] if you change to use it again
}*/
for(i=4;i<tam;i+=8) {
memcpy(v,&buffer2[i],8);
decrypt(v,k);
}
...
I don't fully understand what you are trying to accomplish, but one problem is here:
char* aux[sizeof(unsigned long)];
// ... some code ...
fread(&aux,sizeof(unsigned long),1,fp);
Understand that char* aux[sizeof(unsigned long)]; means that you are declaring a double pointer, but fread() prototype states that the destination is a single pointer:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
so what you should be doing instead is:
char aux[sizeof(unsigned long)];
// ... some code ...
fread(aux,sizeof(unsigned long),1,fp);
Don't complicate things that are not complicated!
You also do this mistake in other parts of your code, you need to re-check everything, ok? Again:
char *buffer2[28568];
fread(&buffer2,1,28568,fp);
should be:
char buffer2[28568];
fread(buffer2, 1, 28568, fp);
// or: fread(buffer2, 1, sizeof(buffer2), fp);
There are some interesting tutorials on pointers and arrays, I suggest you read some.

Manage data inside a buffer

I'm using this code to read a file into a buffer. The file is full of structs of evaluacion type (including some char and int variables).
Now I have the whole file in a buffer, how can I find the values of one variable in the buffer now?
For example buf.notamedia < 4. There are supposed to be many of them inside the file.
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes = 1;
int nbytese = 0;
evaluacion buf;
struct stat datos;
fstat(fd, &datos);
printf("Size of file = %d \n", datos.st_size);
char *buffer = (char *)malloc(datos.st_size);
int actual = read(fd, buffer, datos.st_size);
printf("actual = %d\n", actual);
if (buf.notamedia >= 4.5 && buf.notamedia < 5)
{
/* ... */
}
}
Any idea is very welcome
I'm doing as you said, but I'm only getting one iteration, I don't know what I'm doing wrong :(
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
printf("Number of structs = %d", (datos.st_size/(sizeof(evaluacion))));
for (i=0;i<(datos.st_size/(sizeof(evaluacion)));i++);
{
printf("Notamedia = %f\n",buffer[i].notamedia);
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
printf("Notamedia = %f\n",buffer[i].notamedia);
}
{
}
}
}
Easiest to define the buffer as a pointer to the data structure and use that to dereference the data (although you should ensure the file size is a multiple of the structure size).
i.e.
evaluacion* buffer = (evaluation*)malloc(datos.st_size);
if(buffer[0].notamedia >= 4.5)
You can then increment the index to access other structures you loaded.
Thanks for the comments, I think I solved the problem, I modified the code:
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes=1;
int nbytese=0;
int i=0;
int n=0;
struct stat datos;
fstat(fd, &datos);
evaluacion buf;
printf("File size = %d \n", datos.st_size);
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
do
{
i++;
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
n=n+1;
/*printf("Notamedia = %f\n",buffer[i].notamedia);
*/
buffer[i].notamedia=5;
}
}while (i<(datos.st_size/(sizeof(evaluacion))));
nbytese=write(fd,buffer,datos.st_size);
printf("Written bytes = %d\n",nbytese);
return(n);
}
Now, If the condition is matched, I'm modifying the buffer. Once I read all the structs I write the file in the disk again, but I still have a problem, every time, instead of write the file in the same position, seems like I'm adding the same information after the old one, so if I read the file once I get 3.5Mb, two times 7MB and so on :S.
Any idea what can I do?
Thanks

Resources