问题
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?
回答1:
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>
.)
回答2:
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;
}
回答3:
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);
}
}
回答4:
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);
回答5:
@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.
回答6:
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.
来源:https://stackoverflow.com/questions/12976733/how-can-i-get-only-txt-files-from-directory-in-c