I have code using boost to list directory contents, iterate through each file, and do some data processing stuff. The results are being printed to an output file ('histFile').
After ~2555 files have been processed, I get the error:
boost::filesystem::directory_iterator::construct: Too many open files: "/Users/.../.../.../directory_with_files"
My code is:
for(int i = 0; i < 10000; i++) {
FILE *histFile;
string outputFileName = "somename";
bool ifRet = initFile(histFile, outputFileName.c_str(), "a"); // 1
fclose(histFile); // 2
}
If I comment out the last two lines above ('1' and '2'), the code finishes fine. Thus it seems copies of 'histFile' are being left open, but I don't understand how! This is the operative part of the method:
bool initFile(FILE *&ofFile, const char *fileName, const char *openType, int overwriteOption) {
if(overwriteOption < 0 || overwriteOption > 2) {
fprintf(stderr, "ERROR: ToolBox - initFile() : unknown 'overwriteOption' (%d), setting to (0)!\n", overwriteOption);
}
// Read-Only
if(openType == "r") {
if(ofFile = fopen(fileName, "r")) { return true; }
fprintf(stderr, "ERROR: Could not open file (%s)!\n", fileName);
return false;
}
// Appending:
if(openType == "a" || openType == "a+") {
// Check if file already exists
if(!fopen(fileName, "r")){
fprintf(stderr, "ERROR: (%s) File does not Exist, cannot append!\n", fileName);
return false;
}
if(ofFile = fopen(fileName, openType)) { return true; }
}
// Writing:
// if file already exists
if(FILE *temp = fopen(fileName, "r")){
if(overwriteOption == 2) {
fprintf(stderr, "ERROR: (%s) File Exists!\n", fileName);
return false;
}
if(overwriteOption == 1) {
}
if(overwriteOption == 0) {
char backupFileName[TB_CHARLIMIT], backupPrefix[TB_CHARLIMIT];
strcpy(backupFileName, fileName); // copy filename
// create a prefix w/ format '<YYYYMMDD>BACKUP_'
DateTime now;
sprintf(backupPrefix, "%s", now.getDateStr().c_str());
strcat(backupPrefix, "BACKUP_");
// add to copied filename, and move file
strcpy(backupFileName, prependFileName(backupFileName, backupPrefix));
moveFile(fileName, backupFileName);
}
fclose(temp);
}
if(ofFile = fopen(fileName, openType)) { return true; }
// Default: Return error and false
fprintf(stderr, "ERROR: Could not open file (%s)!\n", fileName);
return false;
}
Am I doing something wrong with pointers/references?
Any help greatly appreciated!
You're leaking a handle in this bit of code when you're testing if the file exists already:
// Appending:
if(openType == "a" || openType == "a+") {
// Check if file already exists
if(!fopen(fileName, "r")){ // <-- the FILE* opened here is leaked
fprintf(stderr, "ERROR: (%s) File does not Exist, cannot append!\n", fileName);
return false;
}
if(ofFile = fopen(fileName, openType)) { return true; }
}
Is there really a reason to make that check? Why not just let the file be created if it doesn't already exist?
Related
I can't figure out what is happening in my program, it's a simple function to clear all the Windows '\r' from a file, putting all the chars in another file and then rename it to substitute the old file. Every time I execute the function the rename() and remove() functions give me "Permission error" even if I had all the file pointers closed and the file on my PC is closed in every program. Here's the code
static bool correctFile(string fileName) {
string name = fileName;
FILE* test = fopen(fileName.c_str(), "rb");
FILE *in, *out;
char stringTest[1000];
bool isWinFile = false;
if (!test) {
return false;
}
fread(stringTest, 1, 1000, test);
fclose(test);
for (size_t i = 0; i < strlen(stringTest) && !isWinFile; i++) {
if (stringTest[i] == '\r') {
isWinFile = true;
}
}
if (isWinFile) {
in = fopen(fileName.c_str(), "rb");
string tempFile = name + ".temp";
out = fopen(tempFile.c_str(), "wb");
if (!in || !out) {
return false;
}
char temp;
while (fread(&temp, sizeof(temp), 1, in) > 0) {
if (temp != '\r') {
fwrite(&temp, sizeof(temp), 1, out);
}
}
fclose(in);
fclose(out);
if (std::remove(fileName.c_str())) {
std::cerr << "Error: " << strerror(errno);
return false;
}
if (std::rename(tempFile.c_str(), fileName.c_str())) {
return false;
}
}
return true;
}
If you find an error in this please tell me, thanks
I found out that the old file and the new file must not be in the same folder for some reason
Disable the virus scanner and see if the problem persists. Some antivirus products block access to files for a couple of microseconds after they have been written or modified. I know of Kaspersky for example.
I have a "Antivirus" retry loop in some of my batch files because of this. So one (ugly) solution is to retry the rename/remove operations a couple of times.
I want to get the last record in a binary file, extract its ID and add one to it to mimic an auto-incrementing ID feature. So for example, if the previous user had an ID of 1, then the next user should have an ID of 2, and so on. The issue is I can't get the last record of the binary file using the code below. How can I go about doing this? Here's my code so far:
#include <stdio.h>
struct Applicant
{
int id;
};
void increment()
{
char fileName = "data.dat";
FILE *file;
// Instantiate the applicant struct
struct Applicant applicant;
// Will contain details of the last applicant in the file
struct Applicant previousApplicant;
// Open the file in 'append binary' mode
file = fopen(fileName, "ab");
// If file does not exist, print error message and exit
if (!file)
{
printf("\nSorry, that file does not exist");
exit(1);
}
// Read the last applicant to get their id
while(1)
{
fread(&previousApplicant, sizeof(previousApplicant), 1, file);
if (feof(file)) { break; }
}
// If there's no previous applicant, set the ID to 100
if (previousApplicant.id == 0)
{
applicant.id = 100;
}
// Otherwise just increment the previous applicant's id and assign it to the new applicant
else
{
applicant.id = previousApplicant.id + 1;
}
fwrite(&applicant, sizeof(applicant), 1, file);
fclose(file);
}
To achieve this, I'm using structs
The way I'd suggest doing it is to call fseek() to seek directly to the last record in the file, read it in to RAM, update it, and write it out again. That way you don't have to read in every record in the file just to update the last one, which would be really inefficient if the file is large and/or you have to perform this operation often.
Something like this:
#include <stdio.h>
#include <stdlib.h>
struct Applicant
{
int id;
};
void increment()
{
const char fileName[] = "data.dat";
// Open the file in 'append binary' mode
FILE *file = fopen(fileName, "a+b");
if (file == NULL)
{
printf("Couldn't open file [%s]\n", fileName);
return;
}
// Seek to the end of the file
if (fseek(file, 0, SEEK_END) != 0)
{
printf("Couldn't seek to the end of the file!\n");
fclose(file);
return;
}
// Will contain details of the last applicant in the file
struct Applicant previousApplicant;
// Check to make sure the file is big enough to hold at least one record
const long fileLengthBytes = ftell(file);
if (fileLengthBytes < sizeof(previousApplicant))
{
printf("File is to short to contain a full record!?\n");
fclose(file);
return;
}
// Check to make sure the file length is an even multiple of the record-length
if ((fileLengthBytes % sizeof(previousApplicant)) != 0)
{
printf("File length (%li) is not a multiple of record size (%zu)!?\n", fileLengthBytes, sizeof(previousApplicant));
fclose(file);
return;
}
// Seek backwards to the start of the last record in the file
if (fseek(file, -sizeof(previousApplicant), SEEK_CUR) != 0)
{
printf("Couldn't seek to the start of the last record in the file!\n");
fclose(file);
return;
}
// Read in the last record in the file
if (fread(&previousApplicant, sizeof(previousApplicant), 1, file) != 1)
{
printf("Couldn't read the last record in the file!\n");
fclose(file);
return;
}
// Increment the record
printf("Incrementing ID of last record in the file from %i to %i\n", previousApplicant.id, previousApplicant.id+1);
previousApplicant.id++;
// Finally, write out the new record in the file with incremented ID
if (fwrite(&previousApplicant, sizeof(previousApplicant), 1, file) != 1)
{
printf("Couldn't write the last record in the file!\n");
fclose(file);
return;
}
// success!
fclose(file);
}
int main(int, char **)
{
increment();
return 0;
}
There were a few problems with your code. You were reading the applicant ID into the applicant struct variable rather than the previousApplicant variable and when reading and writing files it is best to separate out the tasks: first open the file for reading, then when you're ready to write, close it and open it for writing.
Here's the modified working code which will do what you want:
#include <stdio.h>
#include <stdlib.h>
struct Applicant
{
int id;
};
void increment()
{
char* fileName = "data.dat";
FILE *file;
// Instantiate the applicant struct
struct Applicant applicant;
// Will contain details of the last applicant in the file
struct Applicant previousApplicant;
// Open the file in 'append binary' mode
file = fopen(fileName, "rb");
// If file does not exist, print error message and exit
if (!file)
{
printf("\nSorry, that file does not exist");
exit(1);
}
// Read the last applicant to get their id
while(1)
{
fread(&previousApplicant, sizeof(applicant), 1, file);
if( feof(file) ) break;
}
// If there's no previous applicant, set the ID to 100
if (previousApplicant.id == 0)
{
applicant.id = 100;
}
// Otherwise just increment the previous applicant's id and assign it to the new applicant
else
{
applicant.id = previousApplicant.id + 1;
}
fclose(file);
FILE* out = fopen(fileName, "ab");
fwrite(&applicant, sizeof(applicant), 1, out);
printf("%d\n", applicant.id);
fclose(out);
}
void main() {
increment();
}
I am not sure I got the logic of what you are trying to do. As pointed above, you can use just fseek() to move the current pointer for the file.
from the [documentation][1]
int fseek(
FILE *stream,
long offset,
int origin
);
int _fseeki64(
FILE *stream,
__int64 offset,
int origin
);
As for the offset: you can use this pre-defined constants: SEEK_CUR meaning the current position in file, SEEK_SET meaning the beginning and SEEK_END pointing, well, to the END of the file. The current offset from the beginning of file you can get by calling fseek()'s sister, ftell(), that returns a long with the position. First byte is 0. You can for sure seek for any position.
An example:
At first consider this code:
int create(const char* f_name, unsigned int n_rec)
{
Applicant one = {100};
FILE* f = fopen(f_name, "wb");
if (f == NULL) return -1;
for (unsigned i = 0; i < n_rec; i += 1, one.id+= 1)
if (fwrite(&one, sizeof(one), 1, f) != 1)
return 1 + i;
fclose(f);
return n_rec;
}; // create()
This function creates the file and writes down the supplied number of IDs. e.g.
create( "x.dat", 300 )
will go as expected and create x.dat and write 300 IDs starting at 100 --- inclusive --- in the file.
Then the following function in the example below reopens the file, get the last ID used and returns it, and you can use it as a prototype:
int get_last_id(const char* f_name)
{
Applicant one = {0};
int res = 0;
FILE* f = fopen(f_name, "rb+");
if (f == NULL) return -1;
res = fseek(f, SEEK_END, SEEK_SET);
if (res != 0) return -2;
res = fseek(f, -(long) (sizeof(one)), SEEK_END);
if (res != 0)
{
printf("res = %d\n", res);
perror("Error in seek()");
return -3;
}
printf("(file position: byte #%ld)\n", ftell(f));
if (fread(&one, sizeof(one), 1, f) != 1) return -4;
fclose(f);
return one.id;
}
The lines you want are these:
Applicant one = {0};
fseek(f, SEEK_END, SEEK_SET);
fseek(f, -(long) (sizeof(one)), SEEK_END);
fread(&one, sizeof(one), 1, f);
You go to the end if file, then goes back 1 record and read it.
sample output
5 Ids written to "sample.dat"
now open file and get the last ID used
(file position: byte #16)
Last ID on "sample.dat" is 104
For this
C code
#include <stdio.h>
typedef struct
{ int id;
} Applicant;
int create(const char*,unsigned);
int get_last_id(const char*);
int main(void)
{
const char* f_name = "sample.dat";
const unsigned initial_size = 5;
int res = 0;
// a few ids are written to file
if ( (res = create(f_name, initial_size)) < 0) return -1;
printf("\
%d Ids written to \"%s\"\n\
now open file and get the last ID used\n",
res, f_name);
// get the last id on file
res = get_last_id(f_name);
if (res < 0)
{
printf("Could not get id from file (%d)\n", res);
return -1;
}
else
printf("Last ID on \"%s\" is % d\n", f_name, res);
return 0;
}
int get_last_id(const char* f_name)
{
Applicant one = {0};
int res = 0;
FILE* f = fopen(f_name, "rb+");
if (f == NULL) return -1;
res = fseek(f, SEEK_END, SEEK_SET);
if (res != 0) return -2;
res = fseek(f, -(long) (sizeof(one)), SEEK_END);
if (res != 0)
{
printf("res = %d\n", res);
perror("Error in seek()");
return -3;
}
printf("(file position: byte #%ld)\n", ftell(f));
if (fread(&one, sizeof(one), 1, f) != 1) return -4;
fclose(f);
return one.id;
}
int create(const char* f_name, unsigned int n_rec)
{
Applicant one = {100};
FILE* f = fopen(f_name, "wb");
if (f == NULL) return -1;
for (unsigned i = 0; i < n_rec; i += 1, one.id+= 1)
if (fwrite(&one, sizeof(one), 1, f) != 1)
return 1 + i;
fclose(f);
return n_rec;
}; // create()
```
[1]: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fseek-fseeki64?view=msvc-160
I'm working on a project with Flash data saving. I'm using SPIFFS library for ESP32, I'm currently attempting to store the data from each line into a String. Since I have control of how many content can go into the file, it won't need more than 3 Strings to store the data. I could easily manage to store the first line content using readStringUntil. But I can't manage to get the content from 2 and 3 line.
For the first line I'm using this code:
//Pegar a primeira linha do arquivo, onde será armazenado o nome do WIFI (ssid)
void first_line (){
file = SPIFFS.open("/wifi.txt", "r");
while (file.available()) {
String first_line = file.readStringUntil('\n');
Serial.print(first_line);
break;
}
file.close();
}
I'm writing the code into the File with this function:
// Escrever mensagem dentro do arquivo
void write_file_info(String message) {
file = SPIFFS.open("/wifi.txt", FILE_WRITE);
if (!file){
Serial.println("Error opening file");
return;
}else{
Serial.println("Success opening file");
}
if (file.println(message)){
Serial.println("File was written");
}else{
Serial.println("File was not written");
}
file.close();
}
And I'm using Append to add the second and third line:
void append_file_info (String message){
file = SPIFFS.open("/wifi.txt", FILE_APPEND);
if (!file){
Serial.println("Erro ao realizar APPEND ao arquivo");
}
if (file.println(message)){
Serial.println("File was added");
}else{
Serial.println("File was not added");
}
file.close();
}
This is the current output, file size is just for manage and "content inside file" is just for reference:
File size: 37
Content inside file:
first line
second line
thrid line
This is how I'm reading the file:
void read_file_info() {
file = SPIFFS.open("/wifi.txt");
Serial.print("\nFile size: ");
Serial.println(file.size());
Serial.print("Content inside file: \n");
while (file.available()){
Serial.write(file.read());
}
Serial.println("\n");
file.close();
delay(3000);
}
I thought on trying to read the data after '\n', but couldn't find any documentation on reading after certain string.
I tried creating a buffer and splitting it later, the output from the buffer is correct but I can't split it into strings correctly:
void second_line (){
file = SPIFFS.open("/wifi.txt", "r");
char buffer[64];
while (file.available()) {
int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
buffer[l] = 0;
Serial.println(buffer);
}
file.close();
}
It would be simpler using vector:
#include <SPIFFS.h>
using namespace std;
void setup() {
Serial.begin(115200);
if (!SPIFFS.begin(true)) {
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
File file = SPIFFS.open("/wifi.txt");
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
vector<String> v;
while (file.available()) {
v.push_back(file.readStringUntil('\n'));
}
file.close();
for (String s : v) {
Serial.println(s);
}
}
void loop() {}
Use v[0] to get first line, v[1] for second line, v[2] for third line and so on.
I could manage to get it working like this:
void all_lines (){
file = SPIFFS.open("/wifi.txt", "r");
int i = 0;
char buffer[64];
String line_one, line_two, line_three;
while (file.available()) {
int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
buffer[l] = 0;
if (i == 0) {
line_one = buffer;
}
if (i == 1) {
line_two = buffer;
}
if (i == 2) {
line_three = buffer;
}
i++;
if (i == 3){
break;
}
}
file.close();
}
I have a C program that finds duplicate files within a directory. The program is executed on the command line and passed 2 arguments. One is the parent directory, and argument two is the file name. It is working code in c, but I have a GUI and other files for "microservices" written in c++.
How would one call this C code from a c++ file?
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
//Compile: gcc dreamduplicatefinder.c -o dreamduplicatefinder.exe
//Run: ./dreamduplicateFinder.exe parent_dir filename...
#define false 0
#define true 1
int duplicateCount = 0;
int FindDuplicates(char* path, char* fileName);
int CompareFiles(char* originalFile, char* currFile);
int main(int argc, char *argv[])
{
//Two additional arguments are expected: Parent dir, file to find duplicates of...
if (argc != 3)
{
printf("Usage: %s 'Base Directory' 'File Name'\n", argv[0]);
return -1;
}
//argv[1] = base dir, argv[2] = file to find duplicates of; e.g argv[1] = /home,
//argv[2] = "file.txt"...
FindDuplicates(argv[1], argv[2]);
printf("\n\nFound %d duplicate(s)\n", duplicateCount);
return 0;
}
int FindDuplicates(char* path, char* fileName)
{
DIR *dir;
struct dirent *dp;
struct dirent *result;
struct stat statp;
char absoluteFilePath[255];
if ((dir = opendir(path)) == NULL)
{
//printf(dir); //error could becuase trying to open shortcut or corrupt folder.
printf("%s\n",path);
perror("Failed to open directory");
return -1;
}
while ((dp = readdir(dir)) != NULL)
{
//readdir returns . and .. which we should ignore...
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
{
//find file full path, relative to base path. e.g, a /home/file.txt...
//copy path to absoluteFilePath...
strcpy(absoluteFilePath, path);
//append / at end...
strcat(absoluteFilePath, "/");
//append filename to path...
strcat(absoluteFilePath, dp->d_name);
//check if the current file is actually file or dir...
stat(absoluteFilePath, &statp);
if (S_ISDIR(statp.st_mode)) //is a directory...
{
//recurse through this dir...
FindDuplicates(absoluteFilePath, fileName);
}
else if (S_ISREG(statp.st_mode)) //is a file...
{
//check for duplicates here...
//compare current file with the file specified by user...
if (strcmp(fileName, absoluteFilePath))
{
if (CompareFiles(fileName, absoluteFilePath))
{
//yes, duplicate; print it...
printf("%s\n", absoluteFilePath);
duplicateCount++;
}
}
} //end else if (S_ISREG(statp.st_mode))...
} //if (strcmp(dp->d_name, ".") && strcmp(dp->d_name,".."))...
} //end while...
closedir(dir);
return 0;
}
int CompareFiles(char* originalFile, char* currFile)
{
//two step comparison: (1) first check size; if not same, return false.
//If equal, (2) compare file content.If equal, return true, false otherwise...
struct stat statOriginal, statCurr;
stat(originalFile, &statOriginal);
stat(currFile, &statCurr);
//Step 1...
if ((int)statOriginal.st_size != (int)statCurr.st_size) //size not same...
return false;
//Step 2...
//size matches, files can be same; confirm it by matching both file contents...
int fdOriginal = open(originalFile, O_RDONLY);
int fdCurr = open(currFile, O_RDONLY);
if (fdOriginal == -1 || fdCurr == -1)
return false; //error occurred, not sure if file is duplicate...
//we will read file in small chunks and compare...
int chunkSize = 1024, bytesRead;
char *bufferOriginal = (char*)malloc(chunkSize * sizeof(char));
char *bufferCurr = (char*)malloc(chunkSize * sizeof(char));
while (true)
{
//read file in chunk...
bytesRead = read(fdOriginal, bufferOriginal, chunkSize);
if (bytesRead <= 0)
break; //end of file...
bytesRead = read(fdCurr, bufferCurr, bytesRead);
//compare buffer...
if (strcmp(bufferOriginal, bufferCurr)) //if content not matching...
return false;
}
return true;
}
My errors include: (from compareFiles function)
2x 'open' identifier not found
2x 'read' identifier not found
The working code for those curious.
Thank you #MarcusMüller & #JesperJuhl
#include "stdafx.h" //there is nothing in this header
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Compile: gcc <name of this file>.cpp -o <nameOfThisFile>.exe
//Run: <nameOfThisFile> parent_dir filename...
#define false 0
#define true 1
int duplicateCount = 0;
int FindDuplicates(char* path, char* fileName);
int CompareFiles(char* originalFile, char* currFile);
int main(int argc, char *argv[])
{
//Two additional arguments are expected: Parent dir, file to find duplicates of...
if (argc != 3)
{
printf("Usage: %s 'Base Directory' 'File Name'\n", argv[0]);
return -1;
}
//argv[1] = base dir, argv[2] = file to find duplicates of; e.g argv[1] = /home,
//argv[2] = "file.txt"...
FindDuplicates(argv[1], argv[2]);
printf("\n\nFound %d duplicate(s)\n", duplicateCount);
return 0;
}
int FindDuplicates(char* path, char* fileName)
{
DIR *dir;
struct dirent *dp;
struct dirent *result;
struct stat statp;
char absoluteFilePath[255];
if ((dir = opendir(path)) == NULL)
{
//possibly trying to open shortcut or corrupt folder typically.
printf("Failed to open directory %s \n",path);
return -1;
}
while ((dp = readdir(dir)) != NULL)
{
//readdir returns . and .. which we should ignore...
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
{
//find file full path, relative to base path. e.g, a /home/file.txt...
//copy path to absoluteFilePath...
strcpy(absoluteFilePath, path);
//append / at end...
strcat(absoluteFilePath, "/");
//append filename to path...
strcat(absoluteFilePath, dp->d_name);
//check if the current file is actually file or dir...
stat(absoluteFilePath, &statp);
if (S_ISDIR(statp.st_mode)) //is a directory...
{
//recurse through this dir...
FindDuplicates(absoluteFilePath, fileName);
}
else if (S_ISREG(statp.st_mode)) //is a file...
{
//check for duplicates here...
//compare current file with the file specified by user...
if (strcmp(fileName, absoluteFilePath))
{
if (CompareFiles(fileName, absoluteFilePath))
{
//yes, duplicate; print it...
printf("This is a duplicate! %s\n", absoluteFilePath);
duplicateCount++;
}
}
} //end else if (S_ISREG(statp.st_mode))...
} //if (strcmp(dp->d_name, ".") && strcmp(dp->d_name,".."))...
} //end while...
closedir(dir);
return 0;
}
int CompareFiles(char* originalFile, char* currFile)
{
//two step comparison: (1) first check size; if not same, return false.
//If equal, (2) compare file content.If equal, return true, false otherwise...
struct stat statOriginal, statCurr;
stat(originalFile, &statOriginal);
stat(currFile, &statCurr);
//Step 1...
if ((int)statOriginal.st_size != (int)statCurr.st_size) //size not same...
return false;
FILE* fdOriginal;
if (fdOriginal = fopen(originalFile, "r")) {
if (fdOriginal == NULL) { fputs("File error", stderr); return false; }
}
else return false; //error occurred, not sure if duplicate
FILE* fdCurr;
if (fdCurr = fopen(currFile, "r")) {
if (fdCurr == NULL) { fputs("File error", stderr); return false; }
}
else return false;
int chunkSize = 1024, objsRead;
char *bufferOriginal = (char*)malloc(chunkSize * sizeof(char));
if (bufferOriginal == NULL) { fputs("Memory error for buff orig", stderr); exit(2); }
char *bufferCurr = (char*)malloc(chunkSize * sizeof(char));
if (bufferCurr == NULL) { fputs("Memory error for buff curr", stderr); exit(2); }
while (true)
{
//read file in chunk...
//std::size_t fread( void* buffer, std::size_t size, std::size_t count, std::FILE* stream );
objsRead = fread(bufferOriginal, sizeof(char), chunkSize , fdOriginal);
if (objsRead <= 0)
break; //end of file...
objsRead = fread(bufferCurr, sizeof(char), objsRead, fdCurr);
//compare buffer...
if (strcmp(bufferOriginal, bufferCurr)) //if content not matching...
return false;
}
return true;
}
You usually just wouldn't do that. You'd wrap it in a C function, and compile it to an object file.
Then you'd include your C header with extern "C" {…}, and just call that function from C++.
When building your executable, you'd link in the object file containing your C function. Done!
Note: C isn't C++, and albeit your code not being illegal in C++ (as far as I can instantly tell), it does very "ugly" things (like #defineing true and false – ugh, that would already be a bad idea in C, to be honest). So, deal with it like you would deal with code in Fortran, or Java, or any other language that has a calling convention that you can use from C++ (which, usually, is the C calling convention): Just use it as an extern object.
Using ::open and ::read should cause the functions to be found.
You may also want to replace the C headers (like "string.h") with their C++ equivalent versions (like "cstring").
Your defines for true and false should also go. In C++ those are proper bools, not integers. This means the return type of CompareFiles should be changed to bool.
And you should wrap duplicateCount in an anonymous namespace - or return it from the function that updates it (either by returning a small struct with two ints, or by using a std::pair or std::tuple) - global variables are evil.
I am trying to read a file from my .cpp file. I am using C libraries, so do not confuse on that.
So the problem is as clear as what I said in the title. fgets method can read the first line but when it comes to the second line, it cannot read neither the second line nor the rest of the file (since it exits when a problem occurs).
You can find the associated part of code:
void read_input()
{
int i = 0, N = 5;
char str[STR_SIZE], line[STR_SIZE];
FILE *fp;
fp = fopen("out", "r");
if (!fp)
{
fprintf(stderr, "error: file could not be opened\n");
exit(1);
}
for (i = 0; i<2; i++)
{
if (fgets(str, STR_SIZE, fp) == NULL)
{
fprintf(stderr, "error: failed at file reading\n");
exit(1);
}
if (feof(fp))
{
fprintf(stderr, "error: not enough lines in file\n");
exit(1);
}
if ((sscanf(str, "%s", line) != 1) )
{
fprintf(stderr, "error: invalid file format\n");
exit(1);
}
printf("%d\t%s\n", i, line);
fclose(fp);
}
}
I believe, the problem is there, because you've used fclose(fp); inside the loop. So, after the very first iteration, the fp is passed to fclose() and for any recurring use of fp in any further iteration will invoke undefined behavior as the fp is not valid anymore.
Solution: Move the fclose(fp); outside the loop.
You are closing the file in the loop! Put the fclose function outside of the loop.
for (i = 0; i<2; i++)
{
....
printf("%d\t%s\n", i, line);
fclose(fp); // <-- here, move out of the loop.
}