Loop through data stored in buffer in C - c

I have a .dat file with two columns, time & channel of audio data. I am trying to just read the column channel, write it in a different .dat file and save it.
In the code, I have stored the file in a buffer and I'm able to read the values in the column. Now I'm trying to put the second column in another file named out.dat, but it looks like it's not writing anything into the file. Here's what I've done.
int main(){
double a=0;
double b=0;
int bufferLength = 330750;
char buffer[bufferLength];
FILE *fp = fopen("original.dat", "r");
if (!fp){
printf("Cant open file\n");
return -1;
}
FILE *outfp= fopen("out.dat", "w");
if(outfp == NULL)
{
printf("Unable to create file\n");
}
while(fgets(buffer, bufferLength, fp)) {
if (2==sscanf(buffer, "%lf %lf", &a,&b)){ // Just printing col 2 //
printf("b: %f\n", b);
}
}
for(bufferLength=0; bufferLength<330750; bufferLength++){
fputs(&bufferLength, outfp);
}
printf("File transferred\n");
fclose(outfp);
fclose(fp);
return 0;
}

First, you can copy the data into the new file and count the numbers with:
int counter = 0;
while (fgets(buffer, bufferLength, fp)) {
if (2 == sscanf(buffer, "%lf %lf", &a, &b)) {
counter += 1;
fprintf(outfp, "%f\n", b);
}
}
Then create an array and read the file again:
double *data = malloc(sizeof(*data) * counter);
if (!data) { /* handle error */ }
rewind(fp); // If rewind is not available use fseek(fp, 0, SEEK_SET)
int index = 0;
while (fgets(buffer, bufferLength, fp)) {
if (2 == sscanf(buffer, "%lf %lf", &a, &b)) {
data[index++] = b; // Just saving b??
}
}
Alternatively, you can combine these 2 loops and use realloc to allocate memory for the array as you go:
double *data = NULL; // Important: needs to be initialized to NULL
int counter = 0;
while (fgets(buffer, bufferLength, fp)) {
if (2 == sscanf(buffer, "%lf %lf", &a, &b)) {
double *temp = realloc(data, sizeof(*data) * (counter + 1));
if (!temp) { /* handle error.... */ }
data = temp;
data[counter++] = b;
fprintf(outfp, "%f\n", b);
}
}

Related

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
}

Print data of a file stored in file pointer in C

I have written content to a file using a file pointer. I would now like to print this data in the form of an array. I am new to programming in C, and it looks like printing file pointers is different.
Here is an example of my code,
int main(){
double a=0;
double b=0;
double c=0;
double d=0;
int bufferLength = 330752;
char buffer[bufferLength];
FILE *fp = fopen("original.dat", "r");
if (!fp){
printf("Cant open the original file\n");
return -1;
}
FILE *fp1 = fopen("24bitnoise.dat", "r");
if (!fp1){
printf("Cant open the noise file\n");
return -1;
}
FILE *outfp= fopen("out.dat", "w");
if(outfp == NULL)
{
printf("Unable to create file\n");
}
while(fgets(buffer, bufferLength, fp)) {
if (2==sscanf(buffer, "%lf %lf", &a,&b)){ // Just printing col 2 //
// printf("b: %f\n", b);
fprintf(outfp, "%0.25f\n", b);
}
}
FILE *noisefp= fopen("outnoise.dat", "w");
if(noisefp == NULL)
{
printf("Unable to create file\n");
}
while(fgets(buffer, bufferLength, fp1)) {
if (2==sscanf(buffer, "%lf %lf", &c,&d)){ // Just printing col 2 //
fprintf(noisefp, "%0.25f\n", d);
}
}
printf("%f", outfp);
printf("File transferred\n");
fclose(outfp);
fclose(fp);
fclose(fp1);
fclose(noisefp);
return 0;
}
I would now like to print the values from *outfp in the form of an array.
OP is attempting, incorrectly, to print the contents of a file with
printf("%f", outfp);
"%f" expects a matching double, not a FILE *.
To print the text contents of a file, line-by-line:
FILE *inf = fopen("out.dat", "r");
if (inf) {
while(fgets(buffer, bufferLength, inf)) {
printf("%s", buffer);
}
fclose(inf);
}
how can I put these values into an array?
The "trick" is how to determine the size of the array.
One simple approach:
size_t count = 0;
while(fgets(buffer, bufferLength, fp)) {
if (2==sscanf(buffer, "%lf %lf", &a,&b)) {
count++;
}
}
double fp_array = malloc(sizeof *fp_array * count);
if (fp_array == NULL) Handle_Out_of_memory(); // Some tbd code
// Read again
rewind(fp);
size_t i = 0;
while(fgets(buffer, bufferLength, fp)) {
if (2==sscanf(buffer, "%lf %lf", &a,&b)) {
fp_array[i++] = b;
}
}
// Use fp_array
free(fp_array); // clean up when done.
A more elegant approach would re-size the allocation as needed and perform only one read pass.

fread can't read an object from file

Task is to read a map from a file and then display it. The binary file begins with 2 floats and continues with objects of this format:
struct Node {
float height;
int terrainType;
float visitsCount;
struct Node *next;
}Node;
And the function doing the reading:
void showMapTerrain(struct Node Node)
{
FILE *fp;
if ((fp = fopen("map.bin", "rb")) == NULL) {
puts("Unable to open file.");
exit(7);
}
float mapLenght, alt;
if (fread(&mapLenght, sizeof(float), 1, fp) != 1) {
puts("Unable to read from file.");
exit(18);
}
if (fread(&alt, sizeof(float), 1, fp) != 1) {
puts("Unable to read from file.");
exit(20);
}
/*Idea with this is to get the 2 floats out of the way so I can start reading the objects with a single fread.*/
char *mapTerrain = (char *)calloc(mapLenght, sizeof(char));
while (1) {
if (fread(&Node, sizeof(struct Node), 1, fp) != 1) {
//But this bit right here fails, it reads 0 objects.
printf("fread: %d\n", fread(&Node, sizeof(struct Node), 1, fp));
puts("Unable to read from file.");
exit(30);
}
*mapTerrain = Node.terrainType;
}
puts("Terrain type map: ");
while (*mapTerrain) {
printf("[%c]", *mapTerrain);
}
free(mapTerrain);
}
The 2 floats are only in the beginning, so they're outside the loop, that reads objects. I'm pretty sure the syntax for the fread is correct, it's unclear to me what the problem is.
Also, it's not required to make a linked list in this function, we're creating an array of numbers (ranging 1-4, hence char*) and then displaying it.
Edit: the function doing the writing:
void addToFile(struct Node Node)
{
FILE *fp;
float mapLenght, alt;
if ((fp = fopen("map.bin", "rb")) == NULL) {
if ((fp = fopen("map.bin", "wb")) == NULL) {
//2 fopens to check if the file exists. If it doesn't, the user has to input the //2 floats in the beginning. Otherwise we skip straight to adding objects in the //file
puts("Unable to open the file.");
exit(7);
}
puts("How long is the map?");
scanf("%f", &mapLenght);
if (fwrite(&mapLenght, sizeof(float), 1, fp) != 1) {
puts("Unable to write to file.");
exit(6);
}
puts("What's the map's altitude?");
scanf("%f", &alt);
if (fwrite(&alt, sizeof(float), 1, fp) != 1) {
puts("Unable to write to file.");
}
fclose(fp);
}
else {
fclose(fp);
}
if ((fp = fopen("map.bin", "ab")) == NULL){
puts("Unable to open file for further writing.");
exit(7);
}
int c = 0;
while (1) {
puts("Inputting data for individual square meters of the map:");
printf("How high is square meter %d?", ++c);
puts("('-1' to stop.)");
scanf("%f", &Node.height);
if (Node.height == -1) {
system("cls");
puts("You've decided to stop adding data.");
break;
}
printf("What's the terrain type of square meter %d?\n", c);
puts("Values allowed: ");
puts("0 - flora");
puts("1 - waste");
puts("2 - water");
puts("3 - road");
puts("4 - building");
Node.terrainType = 7;
while (1) {
scanf("%d", &Node.terrainType);
if (Node.terrainType < 0 || Node.terrainType>4) {
puts("Invalid data.");
}
else {
break;
}
}
printf("What's the daily visit count for square meter %d?", c);
scanf("%f", &Node.visitsCount);
if (fwrite(&Node, sizeof(Node), 1, fp) != 1) {
//Unlike the other function, everything here works properly, even this fwrite
puts("Error writing data to file.");
exit(6);
}
}
}
My apologies, but I made a very dumb mistake. fread was reading objects just fine, it returned 0 when it got to EOF. I assumed it returned 0 on the first iteration. Fix is bellow:
int *mapTerrain = (int *)calloc(mapLenght, sizeof(int));
int i = 0;
while (1) {
if (fread(&Node, sizeof(struct Node), 1, fp) != 1) {
break;
}
mapTerrain[i] = Node.terrainType;
i++;
}
puts("Map by terrain type: ");
int n;
for (n = 0; n < i; n++) {
printf("[%d]", mapTerrain[n]);
}
puts("");
free(mapTerrain);

How to edit .csv files in C

I'm new at programming, and I need help in my C project. I have to search for a city, confirm it exists in the first file (city.csv), and take its id from there. Then I have to match that id with the corresponding one in the second file (meteo.csv), and then edit its weather information, that is in that second file. However, I don't know how I can take the city id from the first file, and then how to edit the second file after obtaining all the new weather informations. Here is the code:
void addInfo() {
FILE * fp;
char id_city[100];
char city[100];
char humidity[100];
char temp_max[100];
char temp_min[100];
char pressure[100];
char date[100];
printf("Name of the city: ");
scanf("%s", city);
// I think it's here that I have to write the code for take the city's id from the first file
if (id_city != NULL) {
printf("Maximun temperature: ");
scanf("%s", temp_max);
printf("Minimun temperature: ");
scanf("%s", temp_min);
printf("Humidity: ");
scanf("%s", humidity);
printf("Pressure: ");
scanf("%s", pressure);
printf("Date, in the format YYYY-MM-DD: ");
scanf("%s", date);
fp = fopen ("meteo.csv", "a");
fprintf(fp, "%s, %s, %s, %s, %s \n", temp_max, temp_min, humidity, pressure, date); //I think there's something wrong here too...
fclose(fp);
printf("Information edited successfully");
}
The file city.csv has 152 lines and 4 columns:
(id_city,city,county,district)
such as
(56,Lisbon,Lisbon,Lisbon)
The file meteo.csv has 152 lines and 7 columns:
(id_meteo_city,id_city,temp_max,temp_min,humidity,pressure,date)
such as
(56,56,14,5,62,1025,2018-02-12)
The first thing I would do is encapsulate the data in a struct, that makes it
easier to map a line of a CSV file into an object representing a line.
If both files city.csv and meteo.csv have different columns, I'd create a
different struct for each file. If both files have the same columns, you could
use the struct. I assume that both files are different and that city has the
format meteo_id,city_id,name.
typedef struct city_t {
int meteo_id;
int city_id;
char name[100]; // no city should have
// longer than 100 chars
} city_t;
typedef struct meteo_t {
int meteo_id;
int city_id;
int tempt_max;
int tempt_mix;
double humidity;
double preassure;
char date[11];
} meteo_t;
Let's assume that both files are well formatted, otherwise you would have to
write code that checks for errors and handles them, that would be the next step
in the exercise, so I'm going to write only the basic version with basic error
recognition.
#include <stdio.h>
#include <string.h>
#include <errno.h>
// takes 2 params, the filename and a pointer
// to size_t where the number of cities is stored
city_t *read_cities(const char *filename, size_t *len)
{
if(filename == NULL || len == NULL)
return NULL;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
return NULL;
}
city_t *arr = NULL, *tmp;
*len = 0;
// assuming that no line will be longer than 1023 chars long
char line[1024];
while(fgets(line, sizeof line, fp))
{
tmp = realloc(arr, (*len + 1) * sizeof *arr);
if(tmp == NULL)
{
fprintf(stderr, "could not parse the whole file %s\n", filename);
// returning all parsed cities so far
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
arr = tmp;
// %99[^\n] is to read up to 99 characters until the end of the line
if(sscanf(line, "%d,%d,%99[^\n]", &(arr[*len].meteo_id),
&(arr[*len].city_id), arr[*len].name) != 3)
{
fprintf(stderr, "Invalid line format (skipping line):\n%s\n", line);
// skip this line, and decrement *len
(*len)--;
continue;
}
// incrementing only when parsing of line was OK
(*len)++;
}
fclose(fp);
// file is empty or
// all lines have wrong format
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
void print_cities(city_t *cities, size_t len, FILE *fp)
{
if(cities == NULL || fp == NULL)
return;
for(size_t i = 0; i < len; ++i)
fprintf(fp, "%d,%d,%s\n", cities[i].meteo_id, cities[i].citiy_id,
cities[i].name);
}
Now I've written the read and write functions for the file citiy.csv assuming the
format meteo_id;city_id;name. The print_cities allows you to print the CSV
content on the screen (passing stdout as the last argument) or to a file
(passing a FILE object as the last argument).
You can use these functions as templates for reading and writing meteo.csv, the
idea is the same.
You can use these function as follows:
int main(void)
{
size_t cities_len;
city_t *cities = read_cities("city.csv", &cities_len);
// error
if(cities == NULL)
return 1;
do_something_with_cities(cities, cities_len);
// update csv
FILE *fp = fopen("city.csv", "w");
if(fp == NULL)
{
fprintf(stderr, "Could not open city.csv for reading: %s\n",
strerror(errno));
free(cities);
return 1;
}
print_cities(cities, cities_len, fp);
fclose(fp);
free(cities);
return 0;
}
Now for your exercise: write a similar function that parses meteo.csv (using
my function as a template shouldn't be that difficult) and parse both files. Now
that you've got them in memory, it's easy to manipulate the data (insert,
update, delete). Then write the files like I did in the example and that's it.
One last hint: how to search for a city:
// returns the index in the array or -1 on error or when not found
int search_for_city_by_name(city_t *cities, size_t len, const char *name)
{
if(cities == NULL || name == NULL)
return -1;
for(size_t i = 0; i < len; ++i)
if(strcmp(name, cities[i].name) == 0)
return i;
// not found
return -1;
}
Now I have given you almost all parts of the assignment, all you have to do is
stick them together and write the same functions for the meteo.csv file.
To edit one field:
void _ERR(char a) {
if (a == "f") printf("\n\tError File !!\n\n");
if (a == "m") printf("\n\tError Memory !!\n\n");
exit(1); }
char* stmm(const char* src) {
char* dst = malloc(strlen(src) + 1);
if (dst == NULL) return NULL;
strcpy(dst, src);
return dst; }
const char* getfield(char* line, int num) {
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
return tok;
}
return NULL; }
void edit_file(char* FName, char* NewValue, int row, int col) {
int i, r = 0, c;
char line[1024];
FILE* fr, * fw;
fr = fopen(FName, "r");
fw = fopen(FName, "r+");
if (fr == NULL|| fw == NULL) _ERR("f");
while (fgets(line, 1024, fr))
{
char* tmp = stmm(line);
if (tmp == NULL) _ERR("m");
for (i = 0, c = 1; i < strlen(tmp); i++) {
if (tmp[i] == 44) c++;
}
for (i = 0; i < c; i++) {
if (r == row && i+1 == col) {
fprintf(fw,"%s", NewValue);
} else {
free(tmp);
tmp = stmm(line);
if (tmp == NULL) _ERR("m");
fprintf(fw,"%s", getfield(tmp, i + 1));
}
(i < c - 1) ? fprintf(fw,",") : fprintf(fw,"\n");
}
free(tmp);
r++;
}
fclose(fr);
fclose(fw); }
edit_file(".\FileName.csv","NewValue",Row,Column);

Using fread to store data into a char buffer

I am working on a project where I need to read data from a binary file. I am trying to store the data into a char buffer. Suppose the binary file consisted of a character, an int and a double what size would the char buffer need to be ? And how would I convert back into int's and doubles ?
I am reading the data into a char buffer because it would improve the speed of my program.
Thanks!
The following example program fread()s the first DATASIZE sets of a char, an int and a float from a file specified on the command line:
typedef struct Data_s {
char c;
int i;
float f;
} Data_t;
#define DATASIZE 3
int main(int argc, char ** argv) {
if (1 >= argc) {
fprintf(stderr, "usage: %s <file name>\n", argv[0]);
return EXIT_SUCCESS;
}
{
FILE * f = fopen(argv[1], "r");
if (!f) {
perror("fopen() failed.");
return EXIT_FAILURE;
}
{
Data_t data[DATASIZE];
size_t sizeData = sizeof(*data);
size_t sizeToRead = sizeof(data)/sizeData;
memset(data, 0, sizeToRead * sizeData);
size_t sizeRead = fread(&data, sizeData, sizeToRead, f);
if (0 != fclose(f))
perror("fclose() failed,");
if (sizeToRead != sizeRead) {
perror("fread() failed.");
return EXIT_FAILURE;
}
for (size_t i = 0; i < sizeToRead; ++ i)
printf("read c=0x%02hhx, i=%d, f=%f from '%s'\n", data[i].c, data[i].i, data[i].f, argv[1]);
}
}
return EXIT_SUCCESS;
}
You can use the fscanf function to read the data from the file straight into eagerly awaiting variables:
char c;
int i;
double d;
FILE *fp = fopen("C:\\example.txt", "rb");
if (fp)
{
fscanf(fp, "%c%d%lf", &c, &i, &d);
fclose(fp);
printf("Character: %c\nInteger: %d\nDouble: %lf\n", c, i, d);
}
EDIT: If you're looking for more info on fscanf, see here
EDIT2: Binary Solution
FILE *fp = fopen("C:\\example.txt", "rb");
if (fp)
{
char buffer[sizeof(int) + sizeof(double) + sizeof(char)];
if (fread(buffer, 1, sizeof(buffer), fp) == sizeof(buffer))
{
char c = *(char*)buffer;
int i = *(int*)(buffer + sizeof(char));
double d = *(double*)(buffer + sizeof(char) + sizeof(int));
}
fclose(fp);
}

Resources