How can I get only txt files from directory in c?

2019-06-24 00:03发布

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?

6条回答
等我变得足够好
2楼-- · 2019-06-24 00:12

@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.

查看更多
乱世女痞
3楼-- · 2019-06-24 00:15

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);
查看更多
The star\"
4楼-- · 2019-06-24 00:22

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>.)

查看更多
劳资没心,怎么记你
5楼-- · 2019-06-24 00:23

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.

查看更多
可以哭但决不认输i
6楼-- · 2019-06-24 00:38

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;
}
查看更多
对你真心纯属浪费
7楼-- · 2019-06-24 00:39

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);
    }
}
查看更多
登录 后发表回答