I'm trying to read a file with some tokens, using fgets and strtok_s, I wanted to use strtok, but it's not safe, and I couldn't find any good example in how to use it. After some checks I've made, what's happening it's reading from the file only the words such as the first word before of the token (i.e. if the string is "1,2,3,4,5,1" and the token is ",", so it would read 1 twice in the same loop, and would exit the while loop.
The code:
int val_to_add = 0;
TreeNode * head = new TreeNode(NIL,NIL,NIL,NIL);
FILE * fp;
char line[MAX_LINE];
char *pstr;
errno_t err;
char * context = NULL;
if (argc == 1)
{
//There was no file option.
}
else
{
if ((err = fopen_s(&fp, argv[1], "r")) != 0)
{
fprintf(stderr, "ERROR!\nCannot open file '%s'.\n",argv[1]);
exit(1);
}
while (fgets(line, MAX_LINE, fp) != NULL)
{
pstr = strtok_s(line, ",", &context);
val_to_add = atoi(pstr);
add_treenode(head, val_to_add);
printf("%s\n",pstr);
}
}
Why is the loop is working only once?
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.
Edit: I got the error. I need to put "books/" before the file name.
I'm reading the files names from a directory and then opening these files one by one.
I read the file and print its contents.
I have written a C++ code for this but its not working. I am not able to find any errors in it.
What am I doing wrong ?
My code -
#include <bits/stdc++.h>
#include <omp.h>
#include <dirent.h>
using namespace std;
int main(int argc, char* argv[]){
DIR *dirp;
struct dirent *dp;
if ((dirp = opendir("books")) == NULL) {
perror("couldn't open '.'");
return 0;
}
do {
errno = 0;
if ((dp = readdir(dirp)) != NULL) {
if(strlen(dp->d_name)>4){
string str;
int count=0;
ifstream in(dp->d_name);
//cout<<dp->d_name<<"....."<<endl;
while (!in.eof() && count<100) {
in >>str;
cout<<str;
count++;
}
in.close();
}
}
} while (dp != NULL);
if (errno != 0)
perror("error reading directory");
(void) closedir(dirp);
return 0;
}
Edit: I got the error. I need to put "books/" before the file name.
I have a problem with the following code:
#include <iostream>
#include <stdio.h>
#include "ISBNPrefix.h"
using namespace std;
int main() {
FILE* file = NULL;
int area = 0, i = 0;
long s;
file = open("swagger.txt");
fscanf(file, "%ld", &s);
cout << s << endl;
}
and here's ISBNPrefix.cpp:
#include <iostream>
#include <stdio.h>
#include "ISBNPrefix.h"
using namespace std;
FILE* open(const char filename[]) {
FILE* file = NULL;
file = fopen("filename", "r");
if (file != NULL)
return file;
else return NULL;
}
my ISBNPrefix.h
FILE* open (const char filename[]);
And the content of swagger.txt is: 123456789
When I try to run it to test if it copies the 123456789 into my variable i get a segmentation fault!
You have problem in your function for opening a file:
FILE* open(const char filename[]) {
FILE* file = NULL;
file = fopen("filename", "r"); <-- here
it should be file = fopen(filename, "r");
Also you designed open function to return NULL if there is no file, but then you don't check its return value once you call it:
file = open("swagger.txt");
if (file == NULL) ... <-- you should check the return value
fscanf(file, "%ld", &s);
Also note that fopen and fscanf are C-style functions. Since you are using C++, there are other more convenient means how to read data from a file. Have a look at std::ifstream. Also when you work with C headers in C++, you should include their C++ wrappers: cstdio, cstdlib, etc.
You need fopen for a start. Where does ISBNPrefix.cpp come into the picture?
This program is printing the directories at the root level
Directory_1
Directory_2
but I want to be able to print the directories within them too
Directory_1
Directory_1_2
Directory_1_3
Directory_2
Directory 2_1
Directory_2_1_1
Directory_4
I am trying to do it recursively but I am finding it hard to pass the Directory_1 as a root so it gets evaluated.. What am i missing?
Here is my output
..
.
Directory_1
Directory_2
Failed to open directory: No such file or directory
Code
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
char *arg_temp;
int printDepthFirst(char *arg_tmp);
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
arg_temp = argv[1];
printDepthFirst(arg_temp);
}
int printDepthFirst(char *arg_tmp)
{
struct dirent *direntp;
DIR *dirp;
if ((dirp = opendir(arg_tmp)) == NULL) {
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
{
printf("%s\n", direntp->d_name);
arg_tmp = direntp->d_name;
}
printDepthFirst(arg_tmp);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
Now, I know some people get irritated when asking questions that they think I am expecting them to code this, you dont need to, if you can tell me theoretically what i need to do.. I will research it although if its a small programmatically fix and you can post that I would really appreaciate it.. but if not.. I would also love to hear about what needs to be done in words..
Thank you
Well this should help:
#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
static int display_info(const char *fpath, const struct stat *sb,
int tflag, struct FTW *ftwbuf)
{
switch(tflag)
{
case FTW_D:
case FTW_DP: puts(fpath); break;
}
return 0; /* To tell nftw() to continue */
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
if (nftw(argv[1], display_info, 20, flags) == -1)
{
perror("nftw");
return 255;
}
return 0;
}
Have a look at what fields struct dirent contains.
The string dirent::d_name is a name of a directory, not it's full path. So, if your directory "C:\Alpha" contains directory "C:\Alpha\Beta", d_name would only contatin "Beta", not "C:\Alpha\Beta". You will have to assemble the full path yourself - appending slash/backslash to your arg_tmp and then appending new directory name, like this:
while ((direntp = readdir (dirp)) != NULL)
{
char *dirname = direntp->d_name;
// Only work with directories and avoid recursion on "." and "..":
if (direntp->d_type != DT_DIR || !strcmp (dirname, ".") || !strcmp (dirname, "..")) continue;
// Assemble full directory path:
char current [strlen (arg_tmp) + 2 + strlen (dirname)];
strcpy (current, arg_tmp);
strcat (current, "\\"); // Replace "\\" with "/" on *nix systems
strcat (current, dirname);
// Show it and continue:
printf ("%s\n", current);
printDepthFirst (current);
}
Also, you should call recursively inside the loop, not outside.
Inside your while loop inside printDepthFirst you might need something like:
if(direntp->d_type == DT_DIR)
printDepthFirst(directp->d_name);
You might perhaps have to worry about .. directories too.
Alternatively, I've found boost::filesystem to work quite well.