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.
Related
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
I need to find number of files and folders in a directory. I'm using MinGW compiler before this I tried to use d_type but I couldn't compile my code.
And I don't care about "." and" .. " directory. I don't wanna calculate them.
So I write a program like this. This program can easily find how many files and folders in a directory.
But When I give a new Name a folder instead of New Folder, New Folder(1). This programs calculate that folders as a file.
What can I do? I really stuck. I have to find how many files and how many folders...
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
int
main(int argc, char *argv[])
{
int file_count = 0;
int dir_count = 0;
struct dirent * entry;
struct stat filestat;
size_t nfiles = 0, ndirs = 0;
DIR *dp;
if (argc != 2)
{
printf("usage: put directory_name\n");
exit(-1);
}
if ((dp = opendir(argv[1])) == NULL)
{
printf("Error: can't open %s\n", argv[1]);
exit(-2);
}
while ((entry= readdir(dp)) != NULL){
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
stat(entry->d_name,&filestat);
if( S_ISDIR(filestat.st_mode) ){
ndirs++;
}
else
nfiles++;
}
closedir(dp);
printf("%lu Files, %lu Directories\n", nfiles, ndirs);
return(0);
}
entry->d_name will contain the filename only, not the full path, so if call stat() it will fail unless that file happens to exist in the current directory.
Also note that your code is not recursive, so it won't count stuff in the subfolders.
I want to write my own code for move(mv) Unix command. I am completely new to C language and apparently lost on how to fix my code. I want to perform actions like renaming a file if both the inputs are file names. If the the dest_folder is a directory I would like to move the file into the directory.
But I am unable to fix code for the particular problem as I am not much familiar with directories and C in particular. The program takes 2 inputs source and destination after which it performs necessary functions. I am apparently able to rename my files but I am unable to move the file to a particular folder for some reason I don't know?
Need help with moving file to a particular directory.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define SBUF 256
#define DBUF 256
int main(int ac, char *argv[])
{
DIR* dir_ptr; // the directory
struct dirent* direntp;
if( ac == 1 )
{
printf("Usage: %s MOVE\n", argv[0] );
exit(0);
}
if(ac>1 && ac<3)
{
printf("Error! few arguments provided " );
exit(0);
}
char src_folder[SBUF];
char dest_folder[DBUF];
strcpy(src_folder, argv[1]);
strcpy(dest_folder, argv[2]);
dir_ptr = opendir("."); //open directory
if ( dir_ptr == NULL )
{
perror( "." );
exit( 1 );
}
while( (direntp = readdir( dir_ptr )) != NULL )
{
if ( strcmp(direntp->d_name, dest_folder) !=0) //search file or directory
{
printf("found the file %s", dest_folder);
break;
}else
printf("not found");
break;
}
rename(src_folder, dest_folder);
closedir( dir_ptr );
return 0;
}
rename(3) does not work the way you want it to work (I don't know why, ask the committee). You cannot do a rename(some_file, some_directory), just as the man-page says.
Just use stat(2) (or lstat(2) if necessary) and check what you have been given. Here is a short, runnable sketch.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
// check if it is the same inode on the same device
#define SAME_INODE(a, b) ((a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)
// ALL CHECKS OMMITTED!
int main(int argc, char **argv)
{
struct stat statbuf_src, statbuf_dest;
char *src, *dest, *new_src, *new_dest;
char *current_directory;
if (argc != 3) {
fprintf(stderr, "usage: %s src dest\n", argv[0]);
exit(EXIT_FAILURE);
}
// work on copy
src = malloc(strlen(argv[1]) + 1);
dest = malloc(strlen(argv[2]) + 1);
strcpy(src, argv[1]);
strcpy(dest, argv[2]);
stat(src, &statbuf_src);
stat(dest, &statbuf_dest);
// there are many more, of course
printf("\"%s\" is a ", src);
if (S_ISREG(statbuf_src.st_mode)) {
puts("a regular file");
}
if (S_ISDIR(statbuf_src.st_mode)) {
puts("a directory");
}
printf("\"%s\" is a ", dest);
if (S_ISREG(statbuf_dest.st_mode)) {
puts("a regular file");
}
if (S_ISDIR(statbuf_dest.st_mode)) {
puts("a directory");
}
if (SAME_INODE(statbuf_dest, statbuf_src)) {
printf("%s and %s are the identical\n", src, dest);
}
// if that is not set you have to do it by hand:
// climb up the tree, concatenating names until the inodes are the same
current_directory = getenv("PWD");
printf("current directory is \"%s\"\n", current_directory);
// I'm pretty sure it can be done in a much more elegant way
new_src = malloc(strlen(src) + 1 + strlen(current_directory) + 1);
strcpy(new_src,current_directory);
strcat(new_src,"/");
strcat(new_src,src);
printf("new_src = %s\n",new_src);
new_dest = malloc(strlen(dest) + 1 + strlen(current_directory) + 1 + strlen(src) + 1);
strcpy(new_dest,current_directory);
strcat(new_dest,"/");
strcat(new_dest,dest);
strcat(new_dest,"/");
strcat(new_dest,src);
printf("new_dest = %s\n",new_dest);
if(rename(new_src,new_dest) != 0){
fprintf(stderr,"rename failed with error %s\n",strerror(errno));
}
free(new_src);
free(new_dest);
free(src);
free(dest);
exit(EXIT_SUCCESS);
}
Edit: added code for the desciption below
At the end you have a the path where you are, the information if the arguments given are directories or regular files and the path. If the source is a regular file and the destination a directory, you concatenate the path with the name of the regular file, the path with the name of the directory and the name of the regular file (your source)
Out of
Path = /home/foo
src = bar
dest = coffee
build
new_src = /home/foo/bar
new_dest = /home/foo/coffee/bar
Such that the call to rename() is
rename(new_src, new_dest);
That way you rename a regular file to a regular file which rename() accepts.
Please be aware that rename() does not work across every filesystem, but most.
Like you know, mv is implemented by rename. rename is a atomic system call that can rename a file to a file , an emtpy directory to an empty directory or a directory to a directory(the dest must be nonentity). So there are following situation to deal with:
mv file1 file2 - use rename function
mv dir1 dir2(nonentity or empty) - use rename function
mv dir1 dir2(not empty) - rename dir1 to dir2/dir1
mv file dir(exist) - rename file to dir/file
mv dir file - illegal operation
can you understand?
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.