2017-04-22 6 views
0

Ich schreibe ein kleines Programm zum Organisieren eines Verzeichnisses in Linux durch Erstellen neuer Verzeichnisse und Speichern von Dateien in ihnen basierend auf dem Dateityp. Ich verstehe, dass ich die rename() Funktion verwenden muss, aber wie kann ich fortfahren, Akten mit unterschiedlichen Namen zu verschieben?Verschieben von Dateien in andere Linux-Verzeichnis

Sagen Sie, wenn ich eine .mkv Datei in meinem Verzeichnis hatte. Mein Programm erkennt den Dateityp und verschiebt die Datei in ein Verzeichnis namens video (innerhalb des Verzeichnisses, in dem ich gerade arbeite). Wie kann ich den Namen der Datei übergeben, so dass sie beim Verschieben der Datei ihren Namen behält?

Unten ist meine beste Schätzung, wie es funktionieren sollte, aber offensichtlich nicht kompilieren. Wie kann ich es so replizieren, dass es kompiliert wird?

Ich habe bereits eine Schleife durch readdir() zu laufen, und innerhalb jedes Zyklus erfasst sie den Dateityp einer jeden Eintrag und verwendet diesen Dateityp der Datei in ein anderes Verzeichnis zu verschieben, so dass die rename() wird innerhalb einer if-Anweisung aufgerufen innerhalb der readdir() Schleife.

DIR *d; 
struct dirent *dp; 
d = opendir("."); 
//if statement with function to find file type 
//if the file is an .mkv, it runs: 
rename(dp->d_name, "./video/%s", dp->d_name); 
//how can I do this in a way that will compile? 

Beispiel:
Wenn ich eine Datei scarface.mkv genannt habe, Es wird ein Verzeichnis video (bereits geschehen) und scarface.mkv in das video Verzeichnis verschieben.

+0

Sie können Formatbezeichner * nicht an 'rename' übergeben (z. B.'% s' ergibt keinen Sinn in 'rename'). Verwenden Sie 'sprintf' oder' snprintf', um den 'newpath' für' scarface.mkv' zu erstellen und übergeben Sie die verkettete Zeichenfolge an 'rename'. Der Prototyp für 'rename' ist' int rename (const char * oldpath, const char * newpath); 'Es liegt an dir, * nul-terminated *' oldpath' und 'newpath' richtig zu erstellen.('man 2 rename' ist dein Freund) –

Antwort

-1

opendir() ist nur die erste Funktion. Es gibt Ihnen eine DIR-Struktur, mit der Sie arbeiten können und sonst nichts. Um die Liste der Dateien zu erhalten, benötigen Sie eine Schleife, um readdir() auszuführen. Siehe die vollständige Dokumentation:

https://www.gnu.org/software/libc/manual/html_node/Accessing-Directories.html#Accessing-Directories

Aber mit glob(), wenn Sie können viel einfacher als opendir(). Siehe:

http://man7.org/linux/man-pages/man3/glob.3.html

+0

Entschuldigung, ich hätte klarstellen sollen, dass ich bereits eine Schleife habe, um readdir() auszuführen, und innerhalb jedes Zyklus erkennt sie den Dateityp jedes Eintrags und benutzt diesen Dateityp zum Verschieben die Datei in ein anderes Verzeichnis, so dass die rename() innerhalb einer if-Anweisung innerhalb der readdir() - Schleife aufgerufen wird. –

+0

Wenn Sie bereits über die Schleife verfügen, durchlaufen Sie das Verzeichnis ordnungsgemäß. Der Kompilierungsfehler muss durch eine falsche Syntax verursacht werden, die Sie verwenden. – trollkill

1

Können Sie nicht das ganze relevante Stück Code liefern? Sie initialisieren dp hier nicht, aber Sie verwenden es im Umbenennungsaufruf.

Umbenennen benötigt 2 Argumente, von denen beide Zeiger auf Strings sind (d. H. Array von Zeichen). Ihr Code verwendet 3.

% s sieht wie eine Formatzeichenfolge aus, aber Sie erweitern das nicht mit z. sprintf und ein zusätzliches Argument zum Ersetzen von% s.

+0

Ich weiß, dass meine Umbenennung falsch ist. Ich versuche Ihnen zu zeigen, was ich zu tun versuche, indem ich ein Verzeichnis mit dem Namen erstelle, den ich in der Variablen "dp-> d_name" gespeichert habe. –

+0

Sie sollten wahrscheinlich stat() das Verzeichnis, und wenn es nicht existiert mkdir() es – Ant

1

Wenn ich von meinem Kommentar fortfahre, wo die meisten neuen C-Programmierer verwirrt werden, ist es, das gesamte Problem nicht zu durchdenken. Sie können einfach nicht erwarten, rename aufrufen und es für den gesamten Prozess kümmern. Die C-Bibliotheksfunktionen machen im Allgemeinen eine Sache und nur eine Sache. Es liegt am Programmierer, den Prozess von Anfang bis Ende zu denken und alle zusätzlichen Teile des Puzzles zu codieren, die nicht durch die Funktionen rename oder readdir bereitgestellt werden.

Zum Beispiel, wenn Sie planen, ein neue Verzeichnisnamen auf geben, müssen Sie Validate, dass das Verzeichnis, das Sie beabsichtigen, zu Dateien zu verschieben, in der Tat nicht vorhanden ist (oder Sie brauchen, um es zu schaffen). Wie testen Sie auf das Vorhandensein des neuen Verzeichnisses? Sie müssen auch bestimmen und validieren das Format für das neue Verzeichnis werden Sie rename Dateien zu. Enthält es eine nachlaufende '/' oder nicht? Wie gehe ich damit um, wenn es funktioniert?

Wenn Sie nur Dateien mit einer spezifischen Extension verschieben möchten, müssen Sie eine Möglichkeit zum Suchen und Abrufen der Erweiterung von jedem von zurückgegebenen Dateinamen entwickeln. Sobald ich die Erweiterung für die aktuelle Datei habe, wie vergleiche ich sie mit der Zielerweiterung?

Schließlich, wie kombiniere ich den Verzeichnisnamen Ich beabsichtige, passende Dateien zu verschieben, mit dem aktuellen Dateinamen, um den vollständigen Pfad zu erstellen, um die Dateien zu verschieben? All dies sind Code-Bits, die Sie bereitstellen müssen, um Dateien von einem Verzeichnis in ein anderes zu verschieben. Ist es schwer zu tun? Nein. Es ist ziemlich einfach, aber Sie müssen auf dieser Ebene durchdenken und eine Mindestanzahl von Validierung geben, um Erfolg/Misserfolg einer einzelnen Datei zu bestimmen, die Sie verschieben möchten.

Anstatt zu gehen, wie man jedes einzelne Teil des Puzzles erstellt, weil ich verstehe, dass Sie Hilfe brauchen, und es hilft, ein vernünftiges "go-by" zu haben, um die verschiedenen Teile des Puzzles in Ihrem Verstand zu zementieren Das folgende ist ein kurzes Beispiel, das das ausführt, was ich verstehe Ihre Frage fragt. Im Folgenden ist der Verzeichnis als ersten Argument zu suchen, die Verlängerungs für als zweiten Argument zu suchen, und dem relativen oder absolute Pfadname keine passenden Dateien als dritten Argument zu bewegen (die Standardwerte sind . (aktuelles Verzeichnis suchen) für Dateinamen mit "mkv" Erweiterungen und auf das Unterverzeichnis video bewegen):

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <limits.h>  /* PATH_MAX */ 
#include <sys/types.h> /* opendir */ 
#include <dirent.h>  /* opendir, readdir */ 
#include <errno.h>  /* errno */ 
#include <fcntl.h>  /* for file constants */ 
#include <unistd.h>  /* open/close */ 

int dir_exists (char *d); 
char *fn_ext (char *fn); 
char *fn_wext (char *s); 
char *stripfwd (char *fn); 

int main (int argc, char **argv) { 

    DIR *dp = opendir (argc > 1 ? argv[1] : ".");/* open directory (. default)*/ 
    struct dirent *de = NULL;     /* ptr to dirent for readdir */ 
    char *srchext = argc > 2 ? argv[2] : "mkv", /* extension to search for */ 
     *newdir = argc > 3 ? argv[3] : "./video",/* ptr newdir (video default)*/ 
     path[PATH_MAX] = "";      /* array for trimmed newdir */ 

    strcpy (path, newdir); /* copy newdir from read-only memory to array */ 
    stripfwd (path);   /* check for trailing '/' & overwrite with '\0' */ 
    if (!dir_exists (path)) { /* validate new directory exists */ 
     fprintf (stderr, "error: directory not found '%s'.\n", path); 
     return 0;    /* or create/validate directory here */ 
    } 

    while ((de = readdir (dp))) /* for each file in directory */ 
    { 
     char *ext = NULL; 

     /* skip dot files */ 
     if (!strcmp (de->d_name, ".") || !strcmp (de->d_name, "..")) 
      continue; 

     if ((ext = fn_ext (de->d_name)) == NULL) /* get file extension */ 
      continue; 

     if (strcmp (srchext, ext) == 0) {   /* if extensions match  */ 
      char newpath[PATH_MAX] = "",   /* char array for newpath */ 
       *fn = fn_wext (de->d_name);  /* ptr to filename only  */ 

      sprintf (newpath, "%s/%s", path, fn); /* create newpath */ 

      errno = 0; 
      if (rename (de->d_name, newpath) == -1) { /* rename/validate file */ 
       fprintf (stderr, "error: move of '%s' to '%s' failed.\n", 
         de->d_name, newpath); 
       /* check errno here */ 
      } 
      else /* output successful result */ 
       printf ("moved '%s' to '%s'.\n", de->d_name, newpath); 
     } 
    } 

    return 0; 
} 

/** atomic test that directory exists (>=1 success, 0 otherwise) 
* NOTE: no directory is actually created. fail occurs instead. 
*/ 
int dir_exists (char *d) 
{ 
    int flags = O_DIRECTORY | O_RDONLY; 
    int mode = S_IRUSR | S_IWUSR; 
    int fd = open (d, flags, mode); 

    if (fd < 0)  /* directory does not exist */ 
     return 0; 
    else if (fd) { /* directory exists, rtn fd */ 
     close (fd); 
    } 

    return fd; 
} 

/** Separates extension component from full filename string. 
* Returns pointer following last '.' as extension, NULL otherwise. 
* Protects against false return of ext followin '.' path. 
* No memory is allocated, create copy of return to preserve. 
*/ 
char *fn_ext (char *fn) 
{ 
    char *sp = NULL;    /* start pointer */ 
    char *ext; 

    if (!fn) return NULL; 
    if ((sp = strrchr (fn, '/'))) /* test for '/' to eliminate '.' in path */ 
     sp++; 
    else 
     sp = fn; 

    if ((ext = strrchr (sp, '.'))) 
    { 
     if (ext == fn)    /* dot file case */ 
      return NULL; 
     ext++; 
    } 
    else 
     ext = NULL; 

    return ext; 
} 

/** Separates filename component (with extension) from full filename string. 
* Returns pointer following last '/' filename, full-string otherwise. 
* No memory is allocated, create copy of return to preserve. 
*/ 
char *fn_wext (char *s) 
{ 
    char *fn; 
    if ((fn = strrchr (s, '/'))) 
     fn++; 
    else 
     fn = s; 

    return fn; 
} 

/** remove forward slash '/' at end of 'fn' */ 
char *stripfwd (char *fn) 
{ 
    size_t len = strlen (fn); 

    while (len && fn[len - 1] == '/') 
     fn[--len] = 0; 

    return fn; 
} 

Beispiel Dateien im aktuellen Verzeichnis

$ l myvideo_* 
-rw-r--r-- 1 david david 0 Apr 21 21:46 myvideo_1.mkv 
-rw-r--r-- 1 david david 0 Apr 21 21:46 myvideo_2.mkv 
-rw-r--r-- 1 david david 0 Apr 21 21:46 myvideo_3.mkv 
-rw-r--r-- 1 david david 0 Apr 21 21:46 myvideo_4.mkv 
-rw-r--r-- 1 david david 0 Apr 21 21:46 myvideo_5.mkv 

Leere 'video' Verzeichnis

$ l video 
total 28 
drwxr-xr-x 2 david david 4096 Apr 21 21:45 . 
drwxr-xr-x 15 david david 24576 Apr 21 21:46 .. 

Compile/Build

$ gcc -Wall -Wextra -pedantic -std=gnu11 -Ofast -o bin/readdir_rename readdir_rename.c 

Beispiel Verwendung/Output

$ ./bin/readdir_rename . mkv video 
moved 'myvideo_2.mkv' to 'video/myvideo_2.mkv'. 
moved 'myvideo_1.mkv' to 'video/myvideo_1.mkv'. 
moved 'myvideo_3.mkv' to 'video/myvideo_3.mkv'. 
moved 'myvideo_4.mkv' to 'video/myvideo_4.mkv'. 
moved 'myvideo_5.mkv' to 'video/myvideo_5.mkv'. 

Verschieben bestätigen

$ l video 
total 28 
drwxr-xr-x 2 david david 4096 Apr 21 21:46 . 
drwxr-xr-x 15 david david 24576 Apr 21 21:46 .. 
-rw-r--r-- 1 david david  0 Apr 21 21:46 myvideo_1.mkv 
-rw-r--r-- 1 david david  0 Apr 21 21:46 myvideo_2.mkv 
-rw-r--r-- 1 david david  0 Apr 21 21:46 myvideo_3.mkv 
-rw-r--r-- 1 david david  0 Apr 21 21:46 myvideo_4.mkv 
-rw-r--r-- 1 david david  0 Apr 21 21:46 myvideo_5.mkv 

Blick über Dinge und lassen Sie mich wissen, wenn Sie Fragen haben. Nichts davon ist schwer für sich allein, aber es gibt eine ganze Menge zu überlegen, um eine einigermaßen robuste Bewegung zu ermöglichen (es gibt viele weitere Validierungen, die Sie hinzufügen können, dies ist als ein minimales Beispiel gedacht).

Verwandte Themen