Searching a string in a binary file in C - c

In this code snippet I'm trying to add a string in a binary file. If the string already exists, I return error, otherwise I add it at EOF. I creataed two functions, void AddNewTeam(FILE* fp, char* newTeam), and int SearchTeam(FILE* fp, char* newTeam) as shown below, but that didn't work. Everytime I enter a string, it is added at EOF, even if is in the binary file.
I think the problem is the fread function, I tried to print the value returned by the fread but it is always 0. Can someone help me trying to understand what's wrong with this code and why it's not working?
void AddNewTeam(FILE* fp, const char* newTeam){
int found;
if((fp = fopen("File.dat", "rb")) == NULL){
fp = fopen("File.dat", "ab");
fclose(fp);
}
printf("\tEnter New Team: ");
scanf("%s", newTeam);
found = SearchTeam(fp, newTeam);
if(found == 0){
if((fp = fopen("File.dat", "ab"))){
fwrite(newTeam, sizeof(newTeam), 1, fp);
printf("\tThe following team has been successfully loaded\n");
fclose(fp);
}
}else if(found == 1){
printf("\tThis team already exists\n");
exit(EXIT_FAILURE);
}
}
int SearchTeam(FILE* fp, const char* newTeam){
char string[MAX][MAX_LENGTH];
int counter, result, found = 0;
if((fp = fopen("File.dat", "rb"))){
fseek(fp, 0, SEEK_SET);
for(counter = 0; !feof(fp); counter++){
if(fread(string[counter], sizeof(string[counter]), 1, fp) == 1){
result = strcmp(newTeam, string[counter]);
if(result == 0){
found = 1; break;
}else if(result != 0){
found = 0;
}
}
}
fclose(fp);
return found;
}else if(fp == NULL){
printf("\tError opening binary file\n");
exit(EXIT_FAILURE);
}
}
This is the main function and the function prototypes
int SearchTeam(FILE* fp, const char* newTeam);
void AddNewTeam(FILE* fp, const char* newTeam);
int main(void){
FILE* fp;
char newTeam[MAX_LENGTH];
AddNewTeam(fp, newTeam);
return 0;
}

You're not appending to the file correctly. The search code expects each team name to be in a block of MAX_LENGTH bytes. But when you write, you do:
fwrite(newTeam, sizeof(newTeam), 1, fp);
newTeam is a pointer, not an array, so sizeof will be the size of a pointer, typically 4 or 8 bytes. You need to write MAX_LENGTH bytes so this will match the way you read from the file.
fwrite(newTeam, MAX_SIZE, 1, fp);

Related

fgets returning null - file parsing

I'm trying to get a program to parse a text file line by line for some data storage (I've tried binary file storage, but having mixed data types in the file seems to mess things up).
I'm trying to save a number of entries contained in hist[], which is an array of the history structure which basically contains a float (.value) and a time_t (.event_Time). Before saving these entries, the number of entries should be saved (currently an int).
So far I can write the file just fine using the following function:
void data_save(int node_Id, int sensor_Id, history *hist, int entries){
FILE *file;
char data_Dir[FILENAME_MAX] = "";
char directory[FILENAME_MAX] = "";
char fileName[FILENAME_MAX] = "";
int length = 0;
//define path of the file
_getcwd(data_Dir, FILENAME_MAX);
strcat(data_Dir, "\\Data");
strcat(directory,"\\Node_");
length = snprintf(NULL, 0,"%d",node_Id);
char str1[length];
sprintf(str1, "%d", node_Id);
strcat(directory,str1);
strcat(fileName,"\\Sensor_");
length = snprintf(NULL, 0,"%d",sensor_Id);
char str2[length];
sprintf(str2, "%d", sensor_Id);
strcat(fileName,str2);
strcat(fileName,".txt");
printf("%s\n", directory);
printf("%s\n", fileName);
//check if the Data directory exists, create it if not
if (directory_exists(data_Dir) == false) {
printf("Making directory\n");
_mkdir(data_Dir);
}
strcat(data_Dir, directory);
//check if the Node directory exists, create it if not
if (directory_exists(data_Dir) == false) {
printf("Making directory\n");
_mkdir(data_Dir);
}
strcat(data_Dir, fileName);
printf("%s\n", data_Dir);
//open the file
file = fopen(data_Dir, "w");
if(file == NULL){
printf("Error while opening file.\n");
exit (1);
}
//Save the number of entries
printf("Saving %d entries\n", entries);
fprintf(file, "%d\n", entries);
//Save each entry in the inverse chronological order
//(ie. latest event first)
for(int i=entries-1; i > -1; i--){
fprintf(file, "%f %ld\n", hist[i].value, hist[i].event_Time);
}
fclose(file);
free(data_Dir);
free(directory);
free(fileName);
printf("Node %d, sensor %d: Data saved Successfully (%d Entries)\n", node_Id, sensor_Id, entries);
return;
}
However, I am getting issues when trying to load the file I've just created using the following function:
history * data_load(int node_Id, int sensor_Id, int *entries){
FILE *file;
char data_Dir[FILENAME_MAX] = "";
char directory[FILENAME_MAX] = "";
char fileName[FILENAME_MAX] = "";
int length = 0;
int entries_Temp;
int maxChar = 1000;
char stream[maxChar];
//define path of the file
_getcwd(data_Dir, FILENAME_MAX);
strcat(data_Dir, "\\Data");
strcat(directory,"\\Node_");
length = snprintf(NULL, 0,"%d",node_Id);
char str1[length];
sprintf(str1, "%d", node_Id);
strcat(directory,str1);
strcat(fileName,"\\Sensor_");
length = snprintf(NULL, 0,"%d",sensor_Id);
char str2[length];
sprintf(str2, "%d", sensor_Id);
strcat(fileName,str2);
//check if the Data directory exists, exit if not
if (directory_exists(data_Dir) == false) {
printf("//Data does not exist\n");
*entries = 0;
return NULL;
}
strcat(data_Dir, directory);
//check if the Node directory exists, exit if not
if (directory_exists(data_Dir) == false) {
printf("//Data//Node%d does not exist\n", node_Id);
*entries = 0;
return NULL;
}
strcat(data_Dir, fileName);
printf("%s\n", data_Dir);
//check if file exists (ie. there has been no previous
//data for the given sensor) exit and return 0
//existing entries
file = fopen(data_Dir, "r");
if(file!=NULL){
printf("No file found for given sensor\n");
*entries = 0;
return NULL;
}
//Read the number of entries in the file
printf("Reading number of entries\n");
printf("%s", fgets(stream, sizeof(stream), file));
printf("%s\n", stream);
*entries = strtol(stream, NULL, 10);
printf("Entries : %d\n", *entries);
if(*entries > 100){
printf("Entries is NOK\n");
exit(1);
}
//create the array of structures containing the data
printf("Creating the data array\n");
history *hist = malloc(*entries * sizeof(history));
//Read the data and copy it to the array
//this has not been tackled yet
printf("Closing file\n");
fclose(file);
printf("Freeing memory (filenames...)\n");
free(data_Dir);
free(directory);
free(fileName);
printf("Node %d, sensor %d: Data loaded Successfully (%d Entries)", node_Id, sensor_Id, *entries);
return hist;
}
From what I can gather, it seems fgets returns NULL every time. I am unsure if the file is being read correctly, but it seems that the program manages to open the file as fopen returns non NULL. I also suspect that my first attempt at this using binary files might have failed for similar reasons, but due to the format, I couldn't check if the error was occuring during writing or reading of the file.
I'd like to get some insight on why fgets is failing. I'd also appreciate any guidance on better ways to handle saving and loading data from files, as I'm only a beginner in C and I'm pretty sure there's some more optimal ways of doing what I'm trying to achieve.
At least these problems:
Off by 1.
With a short buffer, sprintf(str1, "%d", node_Id); is undefined behavior (UB) and rest of code is all suspect.
length = snprintf(NULL, 0,"%d",node_Id);
// char str1[length];
char str1[length + 1];
sprintf(str1, "%d", node_Id);
...
//char str2[length];
char str2[length+1];
Bad free
Do not call free() on something that lacks a matching *alloc().
//free(data_Dir);
//free(directory);
//free(fileName);
Suggest simplify string code.
E.g. filename
char fileName[FILENAME_MAX];
int length = snprintf(fileName, sizeof fileName, "%s%d%s",
"\\Sensor_", sensor_Id, ".txt");
if (length < 0 || length >= sizeof fileName) {
Handle_BufferTooSmall_Error();
}
else {
printf("%s\n", fileName);
}

Compare two binary files in C

I am writing a program to compare two binary files and plot the first difference. I want to read 16 bytes of data from each file continuously and compare them. For that I am storing 16 bytes from both file into char *buffer1, buffer2. When I print the output I am getting that buffer1 has both the data of file1 and file2.
The code is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void printConversion(char *buf1, char *buf2) {
size_t len = strlen(buf1);
char *binary = malloc(len * 8 + 1);
binary[0] = '\0';
for (size_t i = 0; i < len; ++i) {
char ch = buf1[i];
for (int j = 7; j >= 0; --j) {
if (ch & (1 << j)) {
strcat(binary,"1");
} else {
strcat(binary,"0");
}
}
}
printf("File1: %s\t", binary);
free(binary);
printf("File2:");
for (int i = 0; i < sizeof(buf2); i++) {
printf("%x", buf2[i] - '0');
}
}
void fileRead(FILE *fp, char *buf, int count) {
fseek(fp, count, SEEK_SET);
fread(buf, 1, 16, fp);
}
int fileSize(FILE *fp) {
fseek(fp, 0, SEEK_END);
int size = ftell(fp) + 1;
return size;
}
int main(int argc, char *argv[]) {
printf("***Binary File Comparator***\n ");
int count = 0;
int index = 0;
char buffer1[16];
char buffer2[16];
char buffer3[16];
char buffer4[16];
// Invalid Number of Arguments
if (argc < 3 || argc > 3) {
printf("Invalid Number of Arguments\n");
}
FILE *fp1, *fp2;
fp1 = fopen(argv[1], "rb");
int size = fileSize(fp1);
int size1 = size;
fclose(fp1);
while (size > 1) {
fp1 = fopen(argv[1], "rb");
fileRead(fp1, buffer1, count);
fclose(fp1);
fp2 = fopen(argv[2], "rb");
fileRead(fp2, buffer2, count);
if (size1 < count) {
int lastSize = count - size1;
count = count + lastSize;
fclose(fp2);
} else {
count = count+16;
fclose(fp2);
}
**printf("buffer1:%s\tbuffer2:%s\n", buffer1, buffer2)**;
size = size - 16;
int result = strcmp(buffer1, buffer2);
if (result != 0) {
for (int i = 0; i < sizeof(buffer1); i++) {
if (buffer1[i] != buffer2[i]) {
int count1 = (count - 16) + i;
index++;
if (index == 1) {
printf("Byte_Offset:%x\n", count1);
fp1 = fopen(argv[1], "rb");
fileRead(fp1, buffer3, count1);
fclose(fp1);
fp2 = fopen(argv[2], "rb");
fileRead(fp2, buffer4, count1);
fclose(fp2);
printConversion(buffer3, buffer4);
break;
}
} else {
continue;
}
}
}
}
}
I have tried to highlight the printf part that is printing my buffer1 and buffer2
The output is as follows:
buffer1:83867715933586928386771593358692 buffer2:8386771593358692
buffer1:49216227905963264921622790596326 buffer2:4921622790596326
buffer1:40267236116867294026723611686729 buffer2:4026723611686729
buffer1:82306223673529228230622367352922 buffer2:8230622367352922
buffer1:25869679356114222586967935611422 buffer2:2586967935611422
Can anybody help what I am doing wrong. Please point me the error and what optimization changes could be done in code. I am at learning stage your feedback will be very helpful.
You are complicating the task by reading 16 bytes at a time. If the goal is to indicate the first difference, just read one byte at a time from both files with getc() this way:
int compare_files(FILE *fp1, FILE *fp2) {
unsigned long pos;
int c1, c2;
for (pos = 0;; pos++) {
c1 = getc(fp1);
c2 = getc(fp2);
if (c1 != c2 || c1 == EOF)
break;
}
if (c1 == c2) {
printf("files are identical and have %lu bytes\n", pos);
return 0; // files are identical
} else
if (c1 == EOF) {
printf("file1 is included in file2, the first %lu bytes are identical\n", pos);
return 1;
} else
if (c2 == EOF) {
printf("file2 is included in file1, the first %lu bytes are identical\n", pos);
return 2;
} else {
printf("file1 and file2 differ at position %lu: 0x%02X <> 0x%02X\n", pos, c1, c2);
return 3;
}
}
In terms of efficiency, reading one byte at a time does not pose a problem if the streams are buffered. For large files, you can get better performance by memory mapping the file contents if available on the target system and for the given input streams.
Not an actual answer, but a word on optimisation. You can increase the speed of the program if you have a bigger buffer. Basically the larger the buffer the faster the program runs HOWEVER the speed you gain from just making it larger will increase logarithmically.
Here is a picture of a graph that will help you understand. Also, what i mentioned applies to any simmilar situation. This includes: Copying files, filling the sound buffer etc. Loading the entire file in your RAM first and operationg on it will usually be faster than loading parts of it. Ofc this is not possible with larger files but still this is what you should aim for if you want speed.
PS: I'm writting here because i don't have rep to comment.
EDIT: I came up with solution but since you did not state what you need to do with your buffer3 and buffer4 i packed it up inside a function.
If you are sure that you are only going to use 16 bytes as a buffer size, remove the nBufferSize parameter and replace the buffer dynamic allocation with a static one.
If after the execution you need the buffers, add them as parameters and keep the nBufferSize param. Keep in mind that if you intend to use them outside the function, you should also allocate them outside the function, so things don't get messy.
/** Returns 0 if files are identical, 1 if they are different and -1 if there
is an error. */
int FileCmp(char* szFile1, char* szFile2, int nBufferSize)
{
FILE *f1, *f2;
f1 = fopen(szFile1, "rb");
f2 = fopen(szFile2, "rb");
// Some error checking?
if (f1 == NULL || f2 == NULL)
return -1;
// You can check here for file sizes before you start comparing them.
// ...
// Start the comparrison.
/// Replace this part with static allocation. --------
char* lpBuffer1 = malloc(sizeof(char)*nBufferSize);
if (lpBuffer1 == NULL) // close the files and return error.
{
fclose(f1);
fclose(f2);
return -1;
}
char* lpBuffer2 = malloc(sizeof(char)*nBufferSize);
if (lpBuffer2 == NULL) // close the files, free buffer1 and return error.
{
free(lpBuffer1);
fclose(f1);
fclose(f2);
return -1;
}
/// --------------------------------------------------
while(1)
{
unsigned int uRead1 = fread(lpBuffer1, sizeof(char), nBufferSize, f1);
unsigned int uRead2 = fread(lpBuffer2, sizeof(char), nBufferSize, f2);
if (uRead1 != uRead2)
goto lFilesAreDifferent;
for(unsigned int i = 0; i < uRead1; i++)
if (lpBuffer1[i] != lpBuffer2[i])
goto lFilesAreDifferent;
if ((feof(f1) != 0) && (feof(f2) != 0))
break; // both files have nothing more to read and are identical.
goto lSkip;
lFilesAreDifferent:
free(lpBuffer1);
free(lpBuffer2);
fclose(f1);
fclose(f2);
return 1;
lSkip:;
}
// The files are the same. Close them, free the buffers and return 0.
free(lpBuffer1);
free(lpBuffer2);
fclose(f1);
fclose(f2);
return 0;
}
A simple Demo:
#define BUFFER_SIZE 16
int main(int nArgs, char** szArgs)
{
if (nArgs != 3)
{
printf("Invalid number of arguments.");
return 0;
}
int nResult = FileCmp(szArgs[1], szArgs[2], BUFFER_SIZE);
switch (nResult)
{
case 0: printf("Files [%s] and [%s] are identical.", szArgs[1], szArgs[2]); break;
case 1: printf("Files [%s] and [%s] are different.", szArgs[1], szArgs[2]); break;
case -1: printf("Error."); break;
}
return 0;
}
EDIT II: Personally, i have never used the C standard FILE library (it was either C++ fstream or pure win32 fileapi) so don't take my word here for granted but fread is the fastest function i could find (faster than fgets or fgetc). If you want even faster than this you should get into OS dependant functions (like ReadFile() for Windows).
chqrlie's solution using getc is absolutely the right way to do this. I wanted to address some points brought up in comments, and find it's best to do that with code. In one comment, I recommend pseudo code which could be confusing (namely, you can't write fwrite(file1...) || fwrite(file2 ...) because of the short circuit. But you can implement the idea of that with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* Compare two files, 16 bytes at a time. (Purely to demonstrate memcmp.
* Clearly, this should be implemented with getc.)
*/
FILE * xfopen(const char *, const char *);
size_t xfread(void *, FILE *, const char *);
int
main(int argc, char **argv)
{
FILE *fp[2];
size_t n[2];
char buf[2][16];
unsigned count = 0;
if(argc != 3) { return EXIT_FAILURE; }
fp[0] = xfopen(argv[1], "r");
fp[1] = xfopen(argv[2], "r");
do {
n[0] = xfread(buf[0], fp[0], argv[1]);
n[1] = xfread(buf[1], fp[1], argv[2]);
if( n[0] != n[1] || (n[0] && memcmp(buf[0], buf[1], n[0]))) {
fprintf(stderr, "files differ in block %u\n", count);
return 1;
}
count += 1;
} while(n[0]);
puts("files are identical");
return 0;
}
size_t
xfread(void *b, FILE *fp, const char *name)
{
size_t n = fread(b, 1, 16, fp);
if(n == 0 && ferror(fp)) {
fprintf(stderr, "Error reading %s\n", name);
exit(EXIT_FAILURE);
}
return n;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = strcmp(path, "-") ? fopen(path, mode) : stdin;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}

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);

Get integer after a character from file

I'm trying to read the number of a txt file like this:
input=20
output=10
hidden=5
....
I tried with this code:
char line[30];
char values[100][20];
int i = 0;
FILE *fp;
fp = fopen("myFile.txt", "r");
if(fp == NULL)
{
printf("cannot open file\n");
return 0;
}
while(fgets(line, sizeof(line), fp) != NULL)
{
sscanf(line, "%[^=]", values[i])
printf("%s\n", values[i]);
i++;
}
fclose(fp);
But I obtain only the first word and never the number after the =.
I get
input
output
etc
instead of
20
10
5
etc
How can I get the number??
This line
sscanf(line, "%[^=]", values[i]);
means "read everything up to, but not including, the = sign into values[i]".
If you are interested in the numeric part after the equal sign, change the call as follows:
sscanf(line, "%*[^=]=%19s", values[i]);
This format line means "read and ignore (because of the asterisk) everything up to, and including, the equal sign. Then read a string of length of up to 19 characters into values[i]".
Demo.
Don't use sscanf() for that, redeclare values to store the integers like
int values[LARGE_CONSTANT_NUMBER];
and after fgets() just use strchr
char *number;
number = strchr(line, '=');
if (number == NULL)
continue;
number += 1;
values[i] = strtol(number, NULL, 10);
you could also use malloc() and realloc() if you wish, to make the values array dynamic.
Try it if you like
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char line[100];
int values[100];
int i;
FILE *fp;
size_t maxIntegers;
fp = fopen("myFile.txt", "r");
if (fp == NULL)
{
perror("cannot open file\n");
return 0;
}
i = 0;
maxIntegers = sizeof(values) / sizeof(values[0]);
while ((fgets(line, sizeof(line), fp) != NULL) && (i < maxIntegers))
{
char *number;
number = strchr(line, '=');
if (number == NULL) /* this line does not contain a `=' */
continue;
values[i++] = strtol(number + 1, NULL, 10);
printf("%d\n", values[i - 1]);
}
fclose(fp);
return 0;
}
with this technique you avoid unecessarily storing the number as a string.

C - Writing to binary failed (rewrites a file)

I'm not sure what I'm doing wrong, trying to write a simple program that encrypts after being ran once renames. When the method is ran twice it is supposed to do the same thing but instead it decrypts the file. The first version worked but it left the old version and made a new version and I wanted a program that I could run once to encrypt and again to decrypt allowing me to change the file extension in the process, for convenience.
When I run the program it crashes on fwrite().
#include <stdio.h>
#include <stdlib.h>
#define KEY '&'
int main(void)
{
FILE *fp; // file pointer
size_t size, test; // file size
char src_file[FILENAME_MAX], dst_file[FILENAME_MAX];
int orig_char, new_char;
int i = 0;
printf("Enter the name of the source file \"file.ext\": ");
scanf("%s", src_file);
if ((fp = fopen(src_file, "rb")) == NULL) { // open file
fprintf(stderr, "Can't open \"%s\"\n", src_file);
exit(EXIT_FAILURE);
}
fseek(fp, 0, SEEK_END); // find the end of file
size = ftell(fp); // file size
fseek(fp, 0, SEEK_SET); // set file position to start
unsigned char buffer[size], *temp = buffer; //buffer
test = fread(buffer, sizeof(buffer[0]), size, fp);
printf("size written: %d, size of file: %d\n", test, size);
if (test != size) {
fprintf(stderr, "Error: operation fwrite failed!\n");
exit(EXIT_FAILURE);
}
fclose(fp);
printf("Enter the name of the destination file \"file.ext\": ");
scanf("%s", dst_file);
if ((fp = fopen(src_file, "wb")) == NULL) {
fprintf(stderr, "Can't open \"%s\"\n", dst_file);
exit(EXIT_FAILURE);
}
puts("Test1");
for (i = 0; (size_t)i < size && orig_char != EOF; i++, temp++) {
orig_char = (int) *temp;
new_char = orig_char ^ KEY;
*temp = new_char;
}
puts("Test3");
test = fwrite(buffer, sizeof(buffer[0]), size, fp);
fclose(fp);
free(buffer);
if ((rename(src_file, dst_file)) != 0)
fprintf(stderr, "Failed to rename file, make sure file doesn't" \
"already exist!\n");
return 0;
}
Here is my final code in case anyone else comes across this problem, I cleaned it up a tad and added a loop feature for offsetting multiple files. I also added some error recovery.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define KEY '&'
int main(void)
{
FILE *fp; // file pointer
size_t size, test; // file size
char src_file[FILENAME_MAX], dst_file[FILENAME_MAX];
char ch = 'Y';
int orig_char, new_char;
int i = 0;
while (toupper(ch) != 'N') {
printf("Enter the name of the source file \"file.ext\": ");
scanf("%s", src_file);
while ((fp = fopen(src_file, "rb")) == NULL) { // open file
fprintf(stderr, "Can't open \"%s\"\n", src_file);
printf("Enter the name of the source file \"file.ext\": ");
scanf("%s", src_file);
}
fseek(fp, 0, SEEK_END); // find the end of file
size = ftell(fp); // file size
fseek(fp, 0, SEEK_SET); // set file position to start
unsigned char buffer[size], *temp = buffer; // buffer
// send file to buffer
test = fread(buffer, sizeof(buffer[0]), size, fp);
printf("size written: %d, size of file: %d\n", test, size);
if (test != size) {
fprintf(stderr, "Error: operation fwrite failed!\n");
system("Press any key to continue");
exit(EXIT_FAILURE);
}
fclose(fp);
while ((fp = fopen(src_file, "wb")) == NULL) {
fprintf(stderr, "Can't open \"%s\"\n", src_file);
printf("Enter the name of the source file \"file.ext\": ");
scanf("%s", src_file);
}
// offset buffer data
for (i = 0; (size_t)i < size && orig_char != EOF; i++, temp++) {
orig_char = (int) *temp;
new_char = orig_char ^ KEY;
*temp = new_char;
}
// write buffer to file
test = fwrite(buffer, sizeof(buffer[0]), size, fp);
fclose(fp);
printf("Enter the file's new name \"file.ext\": ");
scanf("%s", dst_file);
while ((rename(src_file, dst_file)) != 0) {
fprintf(stderr, "Failed to rename file, make sure file doesn't already exist!\n");
}
printf("size written: %d, size of file: %d\n", test, size);
printf("File Successfully offset\n\n");
printf("Would you like to continue: ");
scanf(" %c", &ch);
}
return 0;
}

Resources