I have to store the bmp filename in an array.
eg: files in the current directory
a.bmp b.bmp c.txt d.bmp xyz.exe ...
Currently my output is:
fname[0]=.
fname[1]=..
fname[2]=a.bmp
fname[3]=b.bmp
fname[4]=c.txt
fname[5]=d.bmp
fname[6]=xyz.exe
desired output:
fname[0]=a.bmp
fname[1]=b.bmp
fname[2]=d.bmp
Here is my code.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int main(int argc, char **argv)
{
char filename[20][256];
DIR *dir;
int i=0,k;
struct dirent *ent;
dir = opendir ("D:\\font\\");
if (dir != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL)
{
strcpy(filename[i],ent->d_name);
i++;
/* save filenames in the array */
}
closedir (dir);
}
for (k=0;k<i;k++)
printf("%s\t %d\n",filename[k],k);
FILE *fp;
if(!(fp=fopen(filename[i],"rb")))
{
//file handling
}
fclose(fp);
return 0;
}
However, this code save all the files of current directory in the array. Could someone help me out how to store only bmp filename in the array?
try using strstr function; here is a reference for it.
char* str2 = ".bmp";
strstr(filename[i],str2);
This will return NULL for all filenames you don't care about.
This will work only if the file names are in the form of *.* .
You have to check ent->d_name before adding to your array. You can do in your while loop using strrchr and strcmp for example
char *pdot = strrchr(ent->d_name, '.');
if (dot && !strcmp(pdot, ".bmp")) {
strcpy(filename[i], ent->d_name);
i++;
}
Also if you need case case-insensitive string comparisons use strcasecmp instead of strcmp
You're accessing filename[i] at a position, where you haven't copied anything at position i (fopen line, but increased recently at the strcpy line). Be carefull (I commented the affected code out).
To compare the sufix of your c-strings you could use strcmpi() if available (it's not part of ISO-C), but because you're using dirent already which is not part of ISO-C also (but in the POSIX) you probably want to use strcasecmp().
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int main(int argc, char **argv){
char filename[20][256];
DIR *dir;
int i=0,k;
struct dirent *ent;
dir = opendir ("D:\\font\\");
if (dir != NULL){
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL){
size_t offset = strlen(ent->d_name)-4;
if((strlen(ent->d_name) >= 4) && (!strcasecmp(ent->d_name[offset], ".bmp"))){
strcpy(filename[i],ent->d_name);
i++;
/* save filenames in the array */
}
}
closedir (dir);
}
for (k = 0; k < i; k++) {
printf("%s\t %d\n",filename[k],k);
}
/*FILE *fp;
if(!(fp=fopen(filename[i],"rb"))){
//file handling
}
fclose(fp);*/
return 0;
}
Related
i am trying to do a program that check a directory and tell me how many txt already exist so i can write a new one sequentially.
What is the best way to do that, and how i do that?
Sorry for my poor english
You can use the dirent header to accomplish this task.
you should iterate through every file in the folder, and then you should just do string manipulation, to get the extension of each file.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int main()
{
const char *dir = ".";//current dir
printf("opening folder\n");
DIR *root_folder = opendir(dir);
if(root_folder == 0) {
printf("Error opening file");
return -1;
}
struct dirent *file;
while((file = readdir(root_folder)) != NULL) {
if(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)
continue;
printf("%s\n", file->d_name);
//you can work with the names here
}
}
As Barmar suggested, you can use the functions opendir() to open the desired directory and readdir() to read its content. readdir() returns a pointer to a dirent struct. More about the struct here. You can later use strrchr() to find the last occurence of . and strcmp() to see if you have a match.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int main(void)
{
int txt_count = 0;
DIR *pdir = NULL;
struct dirent *dp = NULL;
char *dir = "."; /* current directory, modify to match your dir */
char *type = NULL;
pdir = opendir(dir); /* opens directory dir */
if (!pdir) /* check if failed to open */
{
fprintf(stderr, "Can't open dir <%s>\n", dir);
exit(EXIT_FAILURE);
}
while ((dp = readdir(pdir))) /* reading contents until NULL */
{
type = strrchr(dp->d_name, '.'); /* get a pointer to the last occurence of '.' in filename */
if (type != NULL && !strcmp(type, ".txt")) /* compare with ".txt",check type for NULL if not found */
{
txt_count++;
}
}
printf("Total txt files in directory </%s> --> %d\n", dir, txt_count);
return 0;
}
int main(int argc, char **argv)
{
char *dirFilename = "/home/sv5071184/sample";
DIR *directory = NULL;
directory = opendir (dirFilename);
if(directory == NULL)
return -1;
struct dirent *dirp;
while ((dirp = readdir (directory)) != NULL) {
if( ! (strcmp (dirp->d_name ,".done") == 0) )
{
printf ("%s\n", dirp->d_name);
}
}
if(closedir(directory) < 0)
return -1;
}
NOTE: i have updated the code . with this code am able to find all the files in a directory whereas i need to find only .done files
The function char *strstr(const char *haystack, const char *needle); give you the position of the substring 'needle' if exists. Then you just have to test if the substring is at the end of the file name.
EDIT:
If you want to keep your code as you did, in the while, change your if condition to:
strstr(dirp->d_name, ".done")!=NULL
Here is how you can find the extension using strrchr:
#include <string.h>
int main(int argc, char **argv)
{
char *dirFilename = "/home/sv5071184/sample";
DIR *directory = NULL;
directory = opendir (dirFilename);
if(directory == NULL)
return -1;
struct dirent *dirp;
while ((dirp = readdir (directory)) != NULL) {
char *dot = strrchr(dirp->d_name, '.'); /* Find last '.', if there is one */
if (dot && (strcmp(dot, ".done") == 0))
{
printf ("%s\n", dirp->d_name);
}
}
if(closedir(directory) < 0)
return -1;
}
Finding files that end in specific string (an extension) is very common thing to do with file names.
For the better or worse, under POSIX standard, file name is not separated into name and extension , and unfortunately C string library does not have a function that is like endsWith in Java or C#.
I think that you should write a simple utility function ends_with(char*, char*) that checks if one string ends with another and use it to check if ends_with(ent->d_name, ".done").
Hope this helps :)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char **argv)
{
char *dirFilename = "/home/sv5071184/sample";
DIR *directory = NULL;
directory = opendir (dirFilename);
if(directory == NULL)
return -1;
struct dirent *dirp;
while ((dirp = readdir (directory)) != NULL) {
if ( strstr(dirp->d_name , ".done" ))
{
printf( "found a .done file: %s\n", dirp->d_name );
}
}
if(closedir(directory) < 0)
return -1;
}
I have used this way and it is working.. thanks everyone
I am fairly new to Linux C Programming and need a little help displaying executable and hidden files using the stat and wordexp functions. ANy help is appreciated. Here is what i have so far:
int main(int argc, char **argv)
{
char fileName[60];
char *pos;
wordexp_t p;
char **w;
int i;
struct stat st;
fprintf(stdout,"Enter file name: ");
fgets(fileName,sizeof(fileName),stdin);
if((pos=rindex(fileName,'\n'))==(fileName+strlen(fileName)-1))
*pos='\0';
wordexp(fileName,&p,0);
w = p.we_wordv;
for(i = 0; i < p.we_wordc; i++)
{
printf("%s\n",w[i]);
wordfree(&p);
}
return 0;
}
On Linux, hidden file begins with dot, so you need to check first character of filename.
Executable files can be filtered by checking file mode (you can read more about it here - look for st_mode field of this structure).
Below simple application, which lists all hidden or executable files in current directory:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
int main(void)
{
DIR *d;
struct dirent *dir;
struct stat buf;
d = opendir(".");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
stat(dir->d_name, &buf);
if ((strlen(dir->d_name) > && dir->d_name[0] == '.') || (buf.st_mode & S_IXGRP || buf.st_mode & S_IXUSR || buf.st_mode & S_IXOTH)
printf("%s\n", dir->d_name);
}
closedir(d);
}
return(0);
}
You should also remember about two things:
directories usually have executable permissions
there are two special directories in linux: '.' and '..'
But I don't know whether you're going to filter it or not.
I have a probleme with a program.
I need to take file name in a folder and put it in a variable.
I tried that:
#define _POSIX_SOURCE
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#undef _POSIX_SOURCE
#include <stdio.h>
int main()
{
DIR *dir;
struct dirent *file;
char fileName;
dir = opendir("../../incoming");
while ((file = readdir(dir)) != NULL)
printf(" %s\n", file->d_name);
fileName = file->d_name;
printf(fileName);
closedir(dir);
return 0;
}
thx
Not very clear what you wanted, I prefer to think you want read the file name into your varible 'fileName' and then handle that varible...
Correct 2 parts:
fileName type should be same as the struct member for assign.
the while loop......
int main(){
DIR *dir;
struct dirent *file;
char fileName[255];
dir = opendir("../../incoming");
while ((file = readdir(dir)) != NULL)
{
printf(" %s\n", file->d_name);
strncpy(fileName, file->d_name, 254);
fileName[254] = '\0';
printf("%s\n", fileName);
}
closedir(dir);
return 0;
}
You need to declare a character array of sufficient size and copy the contents of the file->d_name into it if you want to save it past the call to closedir().
If you want to simply print the name,
printf("%s\n", file->d_name);
would accomplish that.
I would like to get names of only *.txt files in given directory, sth like this:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char **argv)
{
char *dirFilename = "dir";
DIR *directory = NULL;
directory = opendir (dirFilename);
if(directory == NULL)
return -1;
struct dirent *ent;
while ((ent = readdir (directory)) != NULL)
{
if(ent->d_name.extension == "txt")
printf ("%s\n", ent->d_name);
}
if(closedir(directory) < 0)
return -1;
return 0;
}
How can I do this in pure unixs c?
Firstly, Unix has no notion of file extensions, so there's no extension member on struct dirent. Second, you can't compare strings with ==. You can use something like
bool has_txt_extension(char const *name)
{
size_t len = strlen(name);
return len > 4 && strcmp(name + len - 4, ".txt") == 0;
}
The > 4 part ensures that the filename .txt is not matched.
(Obtain bool from <stdbool.h>.)
You can use the glob() function call for that. More info using your favourite search engine, Linux man pages, or here.
#include <glob.h>
#include <stdio.h>
int main(int argc, char **argv) {
const char *pattern = "./*.txt";
glob_t pglob;
glob(pattern, GLOB_ERR, NULL, &pglob);
printf("Found %d matches\n", pglob.gl_pathc);
printf("First match: %s\n", pglob.gl_pathv[0]);
globfree(&pglob);
return 0;
}
Possibility:
while ((ent = readdir (directory)) != NULL)
{
const size_t len = strlen(ent->d_name);
if (len > 4 &&
ent->d_name[len - 4] == '.' &&
ent->d_name[len - 3] == 't' &&
ent->d_name[len - 2] == 'x' &&
ent->d_name[len - 1] == 't')
{
printf ("%s\n", ent->d_name);
}
}
You're almost there, you just need to check if the filename ends with .txt. One way to do that is to use strcmp, strcasecmp, or memcmp:
while ((ent = readdir (directory)) != NULL)
{
int len = strlen(ent->d_name);
if(len > 4 && memcmp(ent->d_name + len - 4, ".txt", 4) == 0) // only checks lowercase
{
// It's a .txt file - now check that it's a regular file
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s/%s", dirFilename, ent->d_name);
struct stat st;
if(stat(filename, &st) == 0 && S_ISREG(st.st_mode))
{
// It's a regular file - process it
}
}
}
It's a good idea to verify that it's a regular file (and not a directory or other type of special file) by calling stat(2) on the full file path and checking the st_mode field with the S_ISxxx macros. Note that the d_type member of the DIR struct returned by readdir isn't always supported, so it's not a good idea to rely on it.
Alternatively, instead of using opendir, readdir, and closedir, you can use the glob(3) function:
glob_t globbuf;
if(glob("/path/to/dir/*.txt", 0, NULL, &globbuf) == 0)
{
int i;
for(i = 0; i < globbuf.gl_pathc; i++)
process_filename(globbuf.gl_pathv[i]);
}
globfree(&globbuf);
#BartFriedrich has points out the glob() function, however he didn't give an example of it's use. Very briefly (and wholly untested) you might try something like this
#include <glob.h>
#include <stdio.h>
void glob_example() {
glob_t g;
int i;
glob("*.txt", 0, NULL, &g);
for (i = 0; i < g.gl_pathc)
printf("matched: %s\n", g.pathv[i]);
globfree(&g)
}
glob() is actually a fairly complicated function in detail, and for more general file matching requirements I probably wouldn't use it, but it does handle your problem effectively. For more information, check out man glob on your linux machine or look at the man page online.
You could write a endswith function:
int endswith (const char *name, const char *suffix)
Just do a reverse-loop (start from the end) throught the suffix and check if each char is the same.