C :: Aufgabe #65

3 Lösungen Lösungen öffentlich

Programm für Dateisuche (Dateifilter)

Anfänger - C von devnull - 29.11.2014 um 08:17 Uhr
Realisiere einen Dateifilter. Das Programm soll einen Verzeichnispfad und eine Namenserweiterung , z.B. ".txt" abfragen und alle dazu passenden Dateien aus dem Verzeichnis auflisten (Dateiname genügt).
Erweiterung: es soll möglich sein mit einem Muster, z.B. "*log.[1-3].gz" nach Dateien zu suchen.

Lösungen:

vote_ok
von devnull (8870 Punkte) - 07.12.2014 um 18:06 Uhr
Variante 1: Suche über Dateinamenserweiterung (Extension)

Konsolenausgabe:


$ ./filter /var/log .log
dpkg.log
alternatives.log
pm-suspend.log
user.log
auth.log
...

Quellcode ausblenden C-Code
/*****************************************
 * filter.c   Dateifilter (File-Extension)
 *****************************************/
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>

#define PATH_LEN 255
#define EXT_LEN 31

int main(int argc, char **argv) {
    DIR* dir;
    struct dirent *dire;
    char dirpath[PATH_LEN+1];
    char filext[EXT_LEN+1];
    char *fp;
    int lext;

	if (argc > 2) {
		strncpy(dirpath, argv[1], PATH_LEN);
		strncpy(filext, argv[2], EXT_LEN);
	} else {		
		printf("Verzeichnispfad: ");
		scanf("%s", dirpath);
		printf("Datei-Extension: ");
		scanf("%s", filext);
	}
	// max. length of file extension
	lext = strlen(filext);
	if (lext > EXT_LEN)
		lext = EXT_LEN;

	// open directory
    if ((dir = opendir(dirpath)) == NULL) {
		fprintf(stderr, "cannot open '%s': %s\n", dirpath,\
		        strerror(errno));
		return 1;
    }
   	// read directory
    while ((dire = readdir(dir)) != NULL) {
		if (errno > 0) {
			fprintf(stderr, "error while reading directory entry: %s\n",\
			        strerror(errno));
			break;
		}
		fp = dire->d_name + strlen(dire->d_name) - lext;
		if (strcmp(fp, filext) == 0)
			printf("%s\n", dire->d_name);
    }
	// close directory
    closedir( dir );
    return 0;
}
1 Kommentar
vote_ok
von devnull (8870 Punkte) - 27.12.2014 um 20:26 Uhr
Die zweite Lösung für den Dateifilter verwendet reguläre Ausdrücke (mit Option -E Extended Regex, sonst Basic Regex).
Beispiele:

Konsolenausgabe:


$ ./filter2 /usr/include 'term.*\.h'
termios.h
term.h
termio.h
term_entry.h
termcap.h

$ ./filter2 -E /var/log '^[a-z]{4}\.log\.[23]\.gz'
kern.log.2.gz
user.log.3.gz
kern.log.3.gz
auth.log.2.gz
user.log.2.gz
dpkg.log.2.gz
dpkg.log.3.gz
auth.log.3.gz


Quellcode ausblenden C-Code
/*****************************************
 * filter2.c   Dateifilter (Regex Match)
 *****************************************/
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <regex.h>
 
#define PATH_LEN 255
#define REGX_LEN 255
 
int main(int argc, char **argv) {
	regex_t regex;
    DIR* dir;
    struct dirent *dire;
    char dirpath[PATH_LEN+1];
    char pattern[REGX_LEN+1];
    int opt_ere=0, opt_ind=1;
 
    if (argc < 3)
		return 1;
	else {	
		if (argc == 4 && argv[1][0] == '-' && argv[1][1] == 'E') {
			opt_ere = 1;
			opt_ind = 2;
		}
        strncpy(dirpath, argv[opt_ind], PATH_LEN);
        strncpy(pattern, argv[opt_ind+1], REGX_LEN);
    }
 
 	// compile extended regular expression
    if (regcomp(®ex, pattern, (opt_ere?REG_EXTENDED:0)|REG_NOSUB) != 0) {
		fprintf( stderr, "could not compile regex\n" );
		return 2;
    }

    // open directory
    if ((dir = opendir(dirpath)) == NULL) {
        fprintf(stderr, "cannot open '%s': %s\n", dirpath,\
                strerror(errno));
        return 3;
    }
    // read directory
    while ((dire = readdir(dir)) != NULL) {
        if (errno > 0) {
            fprintf(stderr, "error while reading directory entry: %s\n",\
                    strerror(errno));
            break;
        }
		if (regexec(®ex, dire->d_name, 0, NULL, 0) == 0)
			printf("%s\n", dire->d_name);
    }
    closedir( dir );
	regfree(®ex);
    return 0;
}
vote_ok
von devnull (8870 Punkte) - 18.01.2015 um 14:07 Uhr
Die dritte Lösung für den Dateifilter verwendet Path-Globbing analog zur (Unix/Linux-)Shell-Kommandozeile. Die Ergebnisse werden sortiert ausgegeben:
Beispiel:

Konsolenausgabe:


$ ./filter /usr/include '[ab]*.h'
aio.h
aliases.h
alloca.h
ar.h
argp.h
argz.h
assert.h
byteswap.h


Quellcode ausblenden C-Code
/*****************************************
 * filter3.c   Dateifilter (Glob Match)
 *****************************************/
#include <unistd.h> 
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <glob.h>
 
#define PATH_LEN 255
#define GLOB_LEN 255
 
int main(int argc, char **argv) {
    char dirpath[PATH_LEN+1];
    char pattern[GLOB_LEN+1];
	glob_t globbuf;
	int cp;
 
    if (argc < 2) {
		fprintf(stderr, "Usage: ./filter <Pfad> <Muster>\n");
		return 1;
	}
    strncpy(dirpath, argv[1], PATH_LEN);
    strncpy(pattern, argv[2], GLOB_LEN);
    if (chdir(dirpath) != 0)
		fprintf(stderr, "chdir %s: %s\n", dirpath, strerror(errno));
    
    // do path globbing and read matched paths
    glob(pattern, 0, NULL, &globbuf);
    for (cp=0; cp < globbuf.gl_pathc; cp++) {
        if (globbuf.gl_pathv[cp] != NULL)
			printf("%s\n", globbuf.gl_pathv[cp]);
    }
	globfree(&globbuf);
    return 0;
}