多くの新しい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
ルック物事を超えると、ご質問があれば私に知らせてください。それ自体は難しいものではありませんが、合理的に頑強な動きを提供するためにはかなり検討する必要があります(追加できる検証が他にもありますが、これは最小の例です)。
*フォーマット指定子*を 'rename'に渡すことはできません(' rename'では '%s'は意味がありません)。 'sprintf'または' snprintf'を使って 'scarface.mkv'の' newpath'を構築し、連結した文字列を 'rename'に渡します。 'rename'のプロトタイプは' int rename(const char * oldpath、const char * newpath); ''ヌル終了* oldpath'と 'newpath'を正しく作成するかどうかです。( 'man 2 rename'はあなたの友人です) –