I want to read all files that I can find in the folder where my executable is, except the runnable file that I'm running. I code the following code but, although this list correctly the files that I have in my folder, I cannot open them with fopen because fopen prints that the file doesn't exists. If I do gedit "path of the file obtained from my program in c" then it opens perfectly from the term. Where is the bug?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
int main (int argc, char **argv) {
//Determining the number of files we have.
//We call to a bash command http://stackoverflow.com/questions/646241/c-run-a-system-command-and-get-output
FILE *fp, *fin;
char path[1035], cwd[1024];
int scanned = 0;
/* Open the command for reading. */
//https://askubuntu.com/questions/370697/how-to-count-number-of-files-in-a-directory-but-not-recursively
//This count soft and hard links also (I think)
fp = popen("ls -F |grep -v /", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
/* Read the output a line at a time - output it. */
//Loop for each file. Be careful! if the exe is inside, it will also be counted!
while (fgets(path, sizeof(path)-1, fp) != NULL) {
printf("Reading file: %s\n", path);
fin=fopen(path,"r");
scanned = 0;
printf("caa");
if (fin != NULL){
printf("AA\n");
fclose(fin);
}
if (!fin)perror("fopen");
printf("Done! \n");
}
/* close */
pclose(fp);
printf("end");
return 0;
}
There are 2 bugs in your code:
when the code updates the "path" variable in your code. It has a newline at the end which needs to be corrected to NUL. This gives an incorrect path.
Something like below can be appended to your code:
while (fgets(path, sizeof(path)-1, fp) != NULL) {
len=strlen(path);
path[len-1]='\0';
Use 'ls -A1', since 'ls -F' adds a '*' in binary name:
fp = popen("ls -A1 |grep -v /", "r");
ok so just in case someone else needs a better approach, I redid the code with the comments I had. Here I let you the new code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
int isDirectory(const char *path) {
struct stat statbuf;
if (stat(path, &statbuf) != 0)
return 0;
return S_ISDIR(statbuf.st_mode);
}
int main (int argc, char **argv) {
FILE *fp, *fin;
char path[1035], cwd[1024];
int scanned = 0;
int ints;
DIR *dir;
struct dirent *ent;
//getcwd prints directory where the app ran.
if ((dir = opendir (getcwd(cwd, sizeof(cwd)))) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
/*Skips . and ..*/
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
if (isDirectory(ent->d_name) != 0) continue;
printf ("Reading file: %s\n", ent->d_name);
scanned = 0;
fin=fopen(ent->d_name,"r");
if (fin != NULL){
while ((scanned = fscanf(fin, "%d", ints)) != EOF) {
if(scanned == 1){
printf("%d\n", ints);
}else {
printf("Whoops! Input format is incorrect!\n");
break;
}
} //LOOP: reading file
fclose(fin);
}
if (!fin)perror("fopen");
printf("Done! \n");
}//LOOP: while opendir
closedir (dir);
} else {
/* could not open directory */
perror ("opendir");
return EXIT_FAILURE;
}
return 0;
}
Related
I understand that popen doesn't allow simultaneous read and write.
To get around this, I created two files, 1.c for writing, and 2.c for reading. The files are included below.
When I run 1.out, I get the expected output on stdout:
bodhi#bodhipc:~/Downloads$ ./1.out
Stockfish 11 64 BMI2 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott
bodhi#bodhipc:~/Downloads$
However, 2.out doesn't give any output on stdout:
bodhi#bodhipc:~/Downloads$ ./2.out
bodhi#bodhipc:~/Downloads$
Where am I going wrong?
1.c:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
char path[1035];
/* Open the command for writing. */
fp = popen("./stockfish", "w");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
fprintf(fp,"uci\n");
/* close */
pclose(fp);
return 0;
}
2.c:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
char path[1035];
/* Open the command for reading. */
fp = popen("./1.out", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
/* Read the output a line at a time - output it.*/
while (fgets(path, sizeof(path), stdout) != NULL) {
printf("%s", path);
printf("Done!\n");
}
/* close */
pclose(fp);
return 0;
}
while (fgets(path, sizeof(path), stdout) != NULL) {
you don't want to read from stdout, instead:
while (fgets(path, sizeof(path), fp) != NULL) {
The following code is supposed to work as follows: print the list of the files in a directory, and print the content of each .c file.
it works fine when executed in UNIX for the same directory: ./a.out ./
However, I was not able to make it work for ./a.out ../differentDir execution.
I know that if the absolute path is provided as an argument, I could use argv[1] for that. However, when it is provided in a form of a relative path I am lost.
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 32768
int main(int argc, char **argv) {
char buf[BUFFSIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dp = opendir(argv[1])) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
Upon opening the file to read, the file pathname needs to also be relative.
// Form prefix for complete relative file name
char filename[MAXPATH];
strcpy(filename, argv[1]);
// append '/' if directory path does not end in '/'
if (TBD_code(filename)) {
strcat(filename, "/");
}
char *end = filename[strlen(filename)];
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
if (findC(dirp->d_name)) {
// append filename to prefix
strcpy(end, dirp->d_name);
fp=fopen(filename, "r");
...
You can use realpath(argv1...) like in this example. realpath will return the absolute path for a relative path.
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv) {
char *path = "../..";
char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
char *res = realpath(path, buff);
if (res) {
printf("This source is at %s.\n", buff);
} else {
perror("realpath");
exit(EXIT_FAILURE);
}
return 0;
}
To include the desired behavior in your program, you can use realpathin your code:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#define BUFFSIZE 32768
int main(int argc, char **argv) {
char buf[BUFFSIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length;
FILE *fp;
char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
char *res = realpath(argv[1], buff);
if ((dp = opendir(res)) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
You could first change to the directory chdir either with relative or absolute path and the get the absolute path via the getcwd
#include <sys/types.h>
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 32768
#define PATH_SIZE 512
int main(int argc, char **argv) {
char buf[BUFFSIZE];
char path[PATH_SIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length, r;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
strcpy(path, argv[1]);
r = chdir(path);
if( r != 0 )
{
printf("Invalid path '%s'\n",path);
exit(1);
}
getcwd(path,PATH_SIZE);
if ((dp = opendir(path)) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
I'm writing a code that reads the first line from a file, where this line includes a path to directory. Then the list_dir() function would enter all subfolders..
I checked the list_dir() and it's works great when I'm sending the path manually -
For example: list_dir ("/home/Desktop/example");
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
static void list_dir (const char *dirPath)
{
// Open the directory in dir_name
DIR *d;
d = opendir (dirPath);
/* Check it was opened. */
printf("%s",dirPath);
if (!d) {
printf ("Cannot open directory\n");
exit (1);
}
while (1) {
struct dirent * entry;
const char * d_name;
/* "Readdir" gets subsequent entries from "d". */
entry = readdir (d);
/* if There are no more entries in this directory */
if (!entry) {
break;
}
/* Print the name of the file and directory. */
d_name = entry->d_name;
printf ("%s/%s\n", dirPath, d_name);
if (entry->d_type & DT_DIR) {
/* Check that the directory is not "d" or d's parent. */
if (strcmp (d_name, "..") != 0 && strcmp (d_name, ".") != 0) {
int path_length;
char path[PATH_MAX];
path_length = snprintf (path, PATH_MAX,"%s/%s", dirPath, d_name);
printf ("%s\n", path);
if (path_length >= PATH_MAX) {
fprintf (stderr, "Path length has got too long.\n");
exit (EXIT_FAILURE);
}
/* Recursively call "list_dir" with the new path. */
list_dir(path);
}
}
}
/* After going through all the entries, close the directory. */
if (closedir (d)) {
printf ("Cannot Close directory");
exit (1);
}
}
void main(int argc, char *argv[])
{
//configuration file path
char* dirPath = argv[1];
FILE *f1 = fopen(dirPath, "r");
if (f1 == NULL) {
printf("Cannot open the file for reading");
exit(1);
}
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, f1)) != -1) {
break;
}
list_dir (line);
fclose (f1);
free(line);
}
example for the txt file:
/home/Desktop/example/
bla bla bla
bla bla bla
As you understand, the problem is when I'm sending the path from main() function, list_dir() can't open the path and I get "Cannot open directory" as an error. Help?
As the commenters above said there is a newline at the end of dirPath and that's why you get Cannot open directory, add strtok(dirPath, "\n"); just before opendir to get rid of the trailing newline.
Also note that you are including some headers more than once and that main should return an int.
I have to know the modification date of some files in a folder. It works, but not with all types of files.
For example it works with .c, .txt, but it doesn't work with other types such .mp4, .jpg and .mp3 (the application I'm creating have to work with multimedia files in general). It prints "Cannot display the time.", so I suppose the problem is on stat(). Thanks.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
char parola[12]="", hash[32]="", esadecimale[1000]="", system3[100]="./md5 ";
int i, len, len2;
int bytes;
char cwd[1024];
int main(void)
{
char t[100] = "";
struct stat b;
DIR *dp;
char destinationFolder[100] = "/Users/mattiazeni/Desktop/Prova/"; //Me la passa da sopra
struct dirent *dir_p;
dp = opendir(destinationFolder);
if ( dp == NULL ) exit(1);
len = strlen(destinationFolder);
for (i=0;i<len;i++) {
system3[i+6]=destinationFolder[i];
}
while( ( dir_p = readdir(dp) ) != NULL ) {
if (dir_p -> d_name[0] != '.') {
//printf("%s\n", dir_p -> d_name);
len2 = strlen(dir_p -> d_name);
for (i=0;i<len2;i++) {
if (dir_p -> d_name[i] == ' '){ //Mi serve per correggere i nomi dei file con spazi
system3[i+len+6]='\\';
}
else system3[i+len+6]=dir_p -> d_name[i];
}
system(system3); //Passa il valore a md5 che calcola l'hash e lo stampa nel file che ci serve insieme al persorso/nome del file
FILE *fp;
if((fp=fopen("userDatabase.txt", "ab"))==NULL) {
printf("Error while opening the file..\n");
fclose (fp);
}
else {
if (!stat(dir_p -> d_name, &b)) {
strftime(t, 100, "%d/%m/%Y %H:%M:%S", localtime( &b.st_mtime)); //C'è ancora qualche errore!!
fprintf(fp, "%s", t);
}
else {
perror(0);
fprintf(fp, "error");
}
fprintf(fp, " initialized");
fprintf(fp, "\n");
}
fclose (fp);
for (i=len+6;i<len+6+len2;i++) {
system3[i]=' ';
}
}
}
closedir(dp);
return 0;
}
Use perror(). Also shouldn't you use st_mtime?
stat:
On success, zero is returned.
On error, -1 is returned, and errno is set appropriately.
99% sure it is because dir_p -> d_name does not exist, which in turn probably is because of a localization issue.
You could do something like:
fprintf(stderr,
"Unable to stat %s\n",
dir_p->d_name);
perror(0);
Also; shouldn't it be ->f_name and not ->d_name if you are checking file status? - (Unless you use d_name for file name off course.)
And your fclose(fp) is outside your fp == NULL check. As you do not return or otherwise abort the flow you risk an SIGSEGV if the fopen fail.
Edit: What do you get with something like this?
#include <unistd.h>
char cwd[1024];
...
} else {
fprintf(stderr,
"Unable to stat '%s'\n",
dir_p->d_name);
perror(0);
if (getcwd(cwd, sizeof(cwd)) == NULL) {
perror("getcwd() error");
} else {
fprintf(stderr,
"in directory '%s'\n",
cwd);
}
}
Edit2:
First; I said getcwd() != NULL should be ==. Se change. (Bad by me.)
The problem in your code. (There is a few more) but regarding stat - you use d_name from readdir. This is only filename; not dir+filename. Thus; you get i.e.:
stat(dir_p->d_name, ...)
Which becomes i.e.:
stat("file.mp4", ...)
Easiest quick-fix (tho dirty) would be:
/* you need to terminate the system string after your for loop */
system3[i + len + 6] = '\0';
system(system3);
if (!stat(system3 + 6, &b)) {
You should use the complete pathname for stat(). Stat does not know which directory you are interested in.
...
char bigbuff[PATH_MAX];
sprintf( bigbuff, "%s/%s", destinationFolder, dir_p->d_name);
rc = stat (bigbuff, &b);
...
This is the final working code in order to scan a directory for files, and print them on a txt output file with the modification date:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
char system3[6]="./md5 ";
int main(void)
{
char t[100] = "";
char bigbuff[200];
struct stat b;
char destinationFolder[100] = "/Users/mattiazeni/Desktop/Prova"; //Me la passa da sopra
DIR *dp;
struct dirent *dir_p;
dp = opendir(destinationFolder);
if ( dp == NULL ) exit(1);
while( ( dir_p = readdir(dp) ) != NULL ) {
if (dir_p -> d_name[0] != '.') {
sprintf( bigbuff, "%s%s/%s",system3, destinationFolder, dir_p->d_name);
system(bigbuff);
FILE *fp;
if((fp=fopen("userDatabase.txt", "ab"))==NULL) {
printf("Error while opening the file..\n");
fclose (fp);
}
else {
sprintf( bigbuff, "%s/%s", destinationFolder, dir_p->d_name);
if (!stat(bigbuff, &b)) {
strftime(t, 100, "%d/%m/%Y %H:%M:%S", localtime( &b.st_mtime)); //C'è ancora qualche errore!!
fprintf(fp, "%s", t);
}
else {
perror(0);
fprintf(fp, "error");
}
fprintf(fp, "\n");
}
fclose (fp);
}
}
closedir(dp);
return 0;
}
Thanks all for the help!
I have to create a listing of the files contained inside a specific directory, I have done the code below(part of a bigger programm), but I would like my programm to ignore any possible folders that could be included inside the directory.
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main ()
{
DIR *dirptr;
struct dirent *entry;
dirptr = opendir ("synchedFolder");
if (dirptr != NULL)
{
while (entry = readdir (dirptr))
{
if(strcmp(entry->d_name,"..")!=0 && strcmp(entry->d_name,".")!=0)
puts (entry->d_name);
}
(void) closedir (dirptr);
}
else
perror ("ERROR opening directory");
}
If you want to list only files, but no directories, you have to add the following check:
entry->d_type == DT_REG
or
entry->d_type != DT_DIR
There's stat() and lstat() and the return value for stat. In the latter, look out for the S_ISDIR macro.
Short answer is the dirent structure includes the necessary information:
if ( entry->d_type == DT_REG)
Check stat (or lstat)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
/* int main (void){ */
int main (int argc, char **argv){
int i,result=0;
struct stat buf;
/* print_S_I_types(); */
for (i=1; i < argc; i++){
if (lstat(argv[i], &buf) < 0) {
fprintf(stderr, "something went wrong with %s, but will continue\n",
argv[i]);
continue;
} else {
if S_ISREG(buf.st_mode){
printf("argv[%d] is normal file\n",i);
}else {
printf("argv[%d] is not normal file\n",i);
}
}
}
return 0;
}
Working code for listing files (without directories):
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
int main()
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("/home/images")) != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL)
{
if(ent->d_type!= DT_DIR)
{
printf ("%s\n", ent->d_name);
}
}
closedir (dir);
}
else
{
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
}