I'm trying to create a function in c which scans the given directory for files of the given format (for example :- _sort.txt) and check if the directory contains that format file or not.
if directory contain file of that format then it should return -1 else 0.
but i am stuck on how to scan the directory.can anyone help me with this.
i am fairly new to c so please bear with me.
operating system :- Linux
you can use strstr to find the pattern in the filename.
don't forget to include these headers:
#include <dirent.h>
#include <string.h>
int find_file(const char *pattern, DIR *dr) {
struct dirent *de;
int found = -1;
while ( (de = readdir(dr)) != NULL) {
// DT_REG is a regular file
if (de->d_type == DT_REG && strstr(de->d_name, pattern) != NULL) {
found = 0;
break;
}
}
return found;
}
any where that you want to use this function you should pass the DIR which is opened with opendir.
int main() {
DIR *d = opendir(".");
const char *pattern = "_sort.txt";
if (find_file(pattern, d) == 0)
printf("found it\n");
else
printf("not found it\n");
return 0;
}
for further information about dirent struct:
man readdir
Related
I was wondering if someone could tell me what I'm doing wrong. This code is supposed to walk though all the directories and files and print them out exactly the same way the UNIX utility FIND does. But for some reason I cant get chdir to change the working directory. I'm trying to limit the number of file descriptors im using.
MAIN
#include <stdio.h>
#include "sfind.h"
#include <unistd.h>
#include <dirent.h>
int main(int argv, char *argc[]){
char cwd[1024]; /* current working directory limit*/
char *path = NULL;
DIR *dp = NULL;
if (getcwd(cwd, sizeof(cwd)) != NULL){ /*allow us to grab the current working directory*/
fprintf(stdout, "Current working dir: %s\n", cwd);
}
else{
perror("getcwd() error");
}
dp = opendir(cwd);
path = ".";
directoryList(dp,path);
return 0;
}
Directory Method Definition
#include <stdio.h>
#include <stdlib.h>
#include "sfind.h"
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
void directoryList(DIR *dp, char *path){
char newPath[PATH_MAX] = {0};/*To store new path*/
struct dirent *element; /*get file name*/
struct stat statbuf;/*determine type of file*/
int status = 0; /*My base case should be once the directory I'm in runs outs out of files I should return;*/
if(dp == NULL){
fprintf(stderr,"FILE DID NOT OPEN!");
exit(-1);
}
/*change the current file directory even if its the first one*/
if((status = chdir(path)) == -1){
printf("ERROOR!");
}/*change the current working directory whether that the same on or not*/
while((element = readdir(dp)) != NULL) /*while current file directory pointer is not equal to zero*/{
/* from here we only have two cases once were reading from the directory either is a file or directory!*/
/*using lstat*/
lstat(element->d_name,&statbuf);
if((S_ISDIR(statbuf.st_mode))) /*is of type directory*/{
if((strcmp(".",element->d_name) == 0) || (strcmp("..",element->d_name) == 0))
continue;
/*create new directory name*/
newPath[0] = '\0';
strcat(newPath,path);/* this will give us the "."*/
strcat(newPath,"/");
strcat(newPath,element->d_name);
printf("%s\n", newPath);
directoryList(dp,newPath); /*recursion*/
file*/
}
else /*Its a file!*/{
printf("%s/%s\n",path,element->d_name);
}
}
}
The issue seems to be with the call to readdir(dp)...
Even though you change the current working directory, you don't update the dp pointer to open the new folder.
Here's a poor-man's working example (I wouldn't do it this way, but it works for small trees).
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void directoryList(DIR *dp, char *path) {
char newPath[PATH_MAX] = {0}; /*To store new path*/
struct dirent *element; /*get file name*/
struct stat statbuf; /*determine type of file*/
int status = 0; /*My base case should be once the directory I'm in runs outs
out of files I should return;*/
DIR *dp_tmp;
if (dp == NULL) {
fprintf(stderr, "FILE DID NOT OPEN!");
exit(-1);
}
while ((element = readdir(dp)) !=
NULL) /*while current file directory pointer is not equal to zero*/ {
/* from here we only have two cases once were reading from the directory
* either is a file or directory!*/
/*using lstat*/
lstat(element->d_name, &statbuf);
if ((S_ISDIR(statbuf.st_mode))) /*is of type directory*/ {
if ((strcmp(".", element->d_name) == 0) ||
(strcmp("..", element->d_name) == 0))
continue;
/*create new directory name*/
newPath[0] = '\0';
strcat(newPath, path); /* this will give us the "."*/
strcat(newPath, "/");
strcat(newPath, element->d_name);
printf("%s\n", newPath);
if ((dp_tmp = opendir(newPath)) == NULL) {
perror("hmm?! ");
exit(1);
}
directoryList(dp_tmp, newPath); /*recursion*/
} else /*Its a file!*/ {
printf("* %s/%s\n", path, element->d_name);
}
}
closedir(dp);
}
int main(void) {
char cwd[1024]; /* current working directory limit*/
char *path = NULL;
DIR *dp = NULL;
if (getcwd(cwd, sizeof(cwd)) !=
NULL) { /*allow us to grab the current working directory*/
fprintf(stdout, "Current working dir: %s\n", cwd);
} else {
perror("getcwd() error");
}
dp = opendir(cwd);
path = ".";
directoryList(dp, path);
return 0;
}
EDIT:
To answer the question in the comment...
Open directories (that should be closed using closedir) are different (and quite unrelated) to the current working directory.
The current working directory is mostly used to resolve the path to any file/folder you're referencing.
Open directory pointers (DIR *) are just pointers to data in the memory. That data relates to a specific directory and you can open a number of directories at the same time.
EDIT2:
A few people in the comments recommended nftw (file tree walk) which is a great alternative to doing it yourself.
If this isn't a learning project, I would recommend it's use.
However, note that POSIX.1-2008 marks ftw as obsolete, so make sure to use the nftw flavor.
Is your goal to learn to implement this yourself, or do you just want results? Because you should take a look at fts.h if you want some very powerful stuff to implement something like find.
I have a directory say A, into which i have sub-directories aa,bb,cc,dd,ee,ff. Each sub directories have a number of .txt, .bin, .dat files. What I want to do is, check each of the sub-directory to see if it contains a text file, if yes return the sub directory name.
The below c script lists the sub directories, but please assist to check within the sub-directory for a txt file.
I'm trying to do this in windows 7-visual studio 2010
#include <dirent.h>
#include <stdio.h>
int main(void)
{
DIR *d;
DIR *f;
struct dirent *dir;
d = opendir("C:\\Users\\xp\\Desktop\\Star1");
if (d) {
while ((dir = readdir(d)) != NULL) {
if (dir->d_name[0] != '.') {
f=opendir(dir->d_name);
if (strstr(dir->d_name , ".txt")) {
printf("%s\n", dir->d_name);
}
}
}
closedir(d);
}
return(0);
}
You could use a flag. If you find a file ending in ".txt" then you set the flag and exit the loop. After the loop you check the flag.
One way to check if a string ends with a specific sub-string:
static const char string_to_find[] = ".txt";
...
// First make sure the filename is long enough to fit the name-suffix
if (strlen(dir->d_name) > strlen(string_to_find))
{
// +strlen(dir->d_name) to get a pointer to the end of dir->d_name
// -strlen(string_to_find) to get a pointer to where the suffix should start
if (strcmp(dir->d_name + strlen(dir->d_name) - strlen(string_to_find),
string_to_find) == 0)
{
// File-name ends with ".txt"
}
}
As an alternative, lazy and Windows-specific solution, you can just let the job to the windows for command this way:
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 1024
int main()
{
char buffer[MAX_LENGTH];
FILE *f = _popen("cmd /c #for /R C:\\Users\\xp\\Desktop\\Star1\\ %i in (.) do #if exist \"%~i\"\\*.txt echo %~fi 2> NUL", "r");
if (f != NULL)
{
while (fgets(buffer, MAX_LENGTH, f) != NULL)
{
int len = strlen(buffer);
if (buffer[len - 1] == '\n')
{
buffer[--len] = '\0';
}
printf("Found: %s\n", buffer);
}
_pclose(f);
}
}
Edit: fixed answer to give directory list instead of .txt files.
Instead of printing the directories you could just put it in an if-statement to check if it's the desired file. If it is: return the directory name, else continue. You can put it all in a for-loop so you can check every directory.
For example:
If(!strcmp(filename, filetofind))
Return dirname
I have files something like this:
file1_a_etc.txt,
file1_b_etc.txt
file2_a_z.txt
file2_b_z.txt
I want to get the size of files with "a" i.e. file2_a_z.txt & file1_a_etc.txt
I have got a large number of files this way, so cant specify each name individually.
I am a beginner at C.
I know how to read the size of a single file. And I am working on windows.
#include <stdio.h>
#include <sys/stat.h> // For struct stat and stat()
struct stat attr;
void main()
{
if(stat("filename.txt", &attr) == 0)
{
float x;
x=(attr.st_size)/1048576.0; //1MB=1048576 bytes
printf("Filesize: %.2f MB", x);
}
else
{
// couldn't open the file
printf("Couldn't get file attributes...");
}
}
For Windows console there is function _findfirst. For first parameter put *a*.txt.
You need to iterate over the files in a given directory while searching for the substring in each file name.
This answer, under the section (Unix/Linux), specifies how to iterate over each filename while comparing for an exact match, you can modify the strcmp function call to strstr to look for a substring.
You could make an Array of strings to store all filenames. Then you can use the strchr function to test, if an 'a' or other character is the name. The use of this function is explained e.g at http://www.tutorialspoint.com/ansi_c/c_strchr.htm
Reading directories programmatically can be done with readdir.
You could do something like this:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
static void lookup(const char *dir)
{
DIR *dirp;
struct dirent *dp;
if ((dirp = opendir(dir)) == NULL) {
perror("couldn't open '.'");
return;
}
do {
errno = 0;
if ((dp = readdir(dirp)) != NULL) {
if (strstr(dp->d_name, "_a_") == NULL)
continue;
(void) printf("found %s\n", dp->d_name);
// Add code to handle the file
}
} while (dp != NULL);
if (errno != 0)
perror("error reading directory");
(void) closedir(dirp);
return;
}
readdir is part of POSIX.1-2001, which is supported by unix/linux-type systems (including OS/X) but only some windows compilers. If you are programming in windows you may have to use another solution.
is there any way to look for some file names with given pattern in a directory and store those names (probably in an array) in C on Linux?
I tried the glob one but I dont know how to save the names besides just print them out..
glob_t g;
g.gl_offs = 2;
glob("*.c", GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
g.gl_pathv[0] = "ls";
g.gl_pathv[1] = "-l";
execvp("ls", g.gl_pathv);
The following program can help you.
How to list files in a directory in a C program?
Afterwards, once the file is displayed. In the display function - printf - Copy the filenames in the array. I guess there is a restriction on the filename size.So that can be the maximum size of the array. In case, you want to save the memory, then you can use realloc and can create the exact number of characters array.
This is a shortcut way to get the data.
#include <dirent.h>
#include <stdio.h>
char name[256][256];
int main(void)
{
DIR *d;
struct dirent *dir;
int count = 0;
int index = 0;
d = opendir(".");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
printf("%s\n", dir->d_name);
strcpy(name[count],dir->d_name);
count++;
}
closedir(d);
}
while( count > 0 )
{
printf("The directory list is %s\r\n",name[index]);
index++;
count--;
}
return(0);
}
I wrote this piece of code that lists all JPG files in the current directory,
#include <string.h>
#include <stdio.h>
#include <dirent.h>
int main() {
char *ptrToSubString;
char fileName[100];
DIR *dir;
struct dirent *ent;
dir = opendir(".");
if (dir != NULL) {
while((ent = readdir(dir)) != NULL) {
strcpy(fileName,ent->d_name);
ptrToSubString = strstr(fileName,".jpg");
if (ptrToSubString != NULL) {
printf("%s",ent->d_name);
} else {
continue;
}
}
closedir(dir);
} else {
perror("");
return 5;
}
return 0;
}
but I'd like to add the functionality to rename the files to a unique filename, or append a unique identifier to the filename.
For instance, If the program lists the following filenames:
facebook.png
instagram.png
twitter.png
I'd like to have them renamed to
facebook-a0b1c2.png
instagram-d3e4f5.png
twitter-a6b7c9.png
any idea on how to achieve this? Any help will be greatly appreciated! Thank you!
Split the name:
*(ptrToSubString++) = 0x0;
Then recombine the name adding a random hex sequence (or maybe a counter?)
snprintf(newFilename, SIZE_OF_NEWFILENAME_BUFFER,
"%s-%06x.%s", fileName, rndhex, ptrToSubString);
call rename() on the new files.
UPDATE
As noticed by Zack, rename will not fail if the new file exists, so after generating newFilename, either stat (mind the race condition -- see Zack's other comment) or open(newFilename, O_WRONLY|O_CREAT|O_EXCL, 0600) must be used to verify the new name isn't in use. If it is, generate a new random and repeat.
Well there is a rename function found in stdio.h. You could use that like this:
/* rename example */
#include <stdio.h>
int main (){
int result;
char oldname[] ="oldname.txt";
char newname[] ="newname.txt";
result= rename( oldname , newname );
if ( result == 0 )
puts ( "File successfully renamed" );
else
perror( "Error renaming file" );
return 0;
}
Just adapt this to your needs. You can also read up more on it here.