2017-04-22 7 views
0

私は、新しいディレクトリを作成し、ファイルタイプに基づいてファイルを格納することで、linuxのディレクトリを整理するための小さなプログラムを作成しています。 rename()機能を使用する必要があることを理解していますが、さまざまな名前のファイルを引き続きどのように移動できますか?別のlinuxディレクトリにファイルを移動する

私のディレクトリに.mkvというファイルがあるとします。私のプログラムは、ファイルタイプを検出し、videoというディレクトリ(私が現在働いているディレクトリ内)にファイルを移動します。ファイルを移動したときにその名前が保持されるように、ファイルの名前をどのように渡すことができますか?

以下は、どのように動作するべきかの私の最高の推測ですが、明らかにコンパイルされません。コンパイルする方法でそれをどのように複製できますか?

私は既にreaddir()を実行するループを持っており、各サイクル内で各エントリのファイルタイプを検出し、そのファイルタイプを使用してファイルを別のディレクトリに移動するため、rename()がifステートメントreaddir()ループ内にあります。

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? 

例:
私はscarface.mkvと呼ばれるファイルを持っていた場合、それはディレクトリvideo(すでに完了)を作成し、videoディレクトリにscarface.mkvを移動します。

+0

*フォーマット指定子*を 'rename'に渡すことはできません(' rename'では '%s'は意味がありません)。 'sprintf'または' snprintf'を使って 'scarface.mkv'の' newpath'を構築し、連結した文字列を 'rename'に渡します。 'rename'のプロトタイプは' int rename(const char * oldpath、const char * newpath); ''ヌル終了* oldpath'と 'newpath'を正しく作成するかどうかです。( 'man 2 rename'はあなたの友人です) –

答えて

-1

opendir()は最初の関数です。これはDIR構造を提供し、他には何もしません。ファイルのリストを取得するには、readdir()を実行するためのループが必要です。完全なドキュメントを参照してください:

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

しかし、グロブを使用して()することができます場合)(opendirなどよりもはるかに簡単です。参照:

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

+0

申し訳ありませんが、私は既にreaddir()を実行するループを持っていることを明確にしておき、各サイクル内で各エントリのファイルタイプを検出し、ファイルを別のディレクトリにコピーします。したがって、rename()はreaddir()ループ内のif文の内部で呼び出されます。 –

+0

すでにループがある場合は、ディレクトリを正しく繰り返しています。コンパイルエラーは、使用している誤った構文によって引き起こされている必要があります。 – trollkill

1

あなたは、コードの全体の関連作品を供給することができませんか?あなたはここでdpを初期化していませんが、リネームコールでそれを使用しています。

renameは2つの引数をとり、どちらも文字列(つまり文字の配列)へのポインタです。あなたのコードは3を使用します。

%sはフォーマット文字列のように見えますが、 sprintfと%sを置き換える追加の引数。

+0

名前の変更が間違っていることを知っています。私は "dp-> d_name"変数に格納されている名前のディレクトリを作成しようとしています。 –

+0

ディレクトリをstat()していなければmkdir()となります – Ant

1

多くの新しいCプログラマーが混乱している私のコメントを続けると、手元の問題全体を考えることができなくなります。 renameに電話して、プロセス全体を処理することは期待できません。 Cライブラリの関数は一般的に1つのことを行います。プログラマは、プロセスを最初から最後まで考えて、renameまたはreaddir関数で提供されていないパズルのすべての追加部分をコーディングする必要があります。例えば

あなたは新しいディレクトリ名を渡すことを予定している場合、あなたはあまりにもファイルを移動しようとするディレクトリが、実際には存在しない(またはあなたがそれを作成する必要がある)ことを検証する必要があります。新しいディレクトリの存在をどうやってテストしますか?あなたはまた、を確認する必要がありますrenameファイルに新しいディレクトリの形式を検証します。末尾に'/'が含まれていますか?どうすればそれを処理するのですか?

のファイルを移動する場合は、readdirが返す各ファイル名から拡張子を確認して取得する方法を開発する必要があります。現在のファイルの拡張子を取得したら、それをターゲット拡張子とどのように比較すればよいですか?

最後に、一致するファイルを移動する予定のディレクトリ名と現在のファイル名を組み合わせて、ファイルを移動する完全なパスを作成するにはどうすればよいですか?これらはすべて、あるディレクトリから別のディレクトリにファイルを移動できるようにするために必要なコードです。それは難しいですか?いいえ、それは簡単ですが、そのレベルで考えて、移動する個々のファイルの成功/失敗を判断するには、検証の最小量を指定する必要があります。

パズルの個々の部分をどのように作成するのかではなく、あなたが助けを必要としていることを理解しているので、合理的な "ゴーイング"以下は、私があなたの質問が尋ねていると理解していることを成し遂げる短い例です。以下は、引数、および引数と任意の一致するファイルを移動する相対又は絶対パス名を検索する最初引数、拡張として検索するディレクトリを取り(デフォルトは."mkv"拡張子を持つファイル名に)現在のディレクトリを検索し、videoサブディレクトリに移動している):

#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; 
} 

例現在のディレクトリ内のファイル

$ 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 

空の 'ビデオ' ディレクトリ

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

コンパイル/ビルド・

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

使用例/出力

$ ./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'. 

確認移動

$ 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 

ルック物事を超えると、ご質問があれば私に知らせてください。それ自体は難しいものではありませんが、合理的に頑強な動きを提供するためにはかなり検討する必要があります(追加できる検証が他にもありますが、これは最小の例です)。

関連する問題