[英]Moving files to different linux directory
我正在編寫一個小程序,通過創建新目錄並根據文件類型將文件存儲在Linux中來組織目錄。 我知道我需要使用rename()
函數,但是如何繼續移動具有不同名稱的文件?
假設我的目錄中有一個.mkv
文件。 我的程序檢測到文件類型,然后將文件移動到名為video
的目錄中(位於我當前使用的目錄內)。 如何傳遞文件名,以便在移動文件時保留其名稱?
關於它應該如何工作,但顯然不能編譯,以下是我的最佳猜測。 如何以可編譯的方式復制它?
我已經有一個循環遍歷readdir()
,並且在每個循環中它都會檢測每個條目的文件類型,並使用該文件類型將文件移動到另一個目錄中,因此在if語句內部調用了rename()
。在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
(已完成)並將scarface.mkv
移至video
目錄。
您不能提供全部相關的代碼嗎? 您不是在這里初始化dp,而是在重命名調用中使用它。
重命名帶有2個參數,這兩個參數都是指向字符串(即字符數組)的指針。 您的代碼使用3。
%s看起來像格式字符串,但是您沒有用sprintf和其他參數替換%s來擴展它。
繼續我的評論,大多數新的C程序員感到困惑的是,沒有考慮到眼前的整個問題。 您根本無法期望調用rename
並讓它負責整個過程。 C庫函數通常只能做一件事,而只能做一件事。 程序員應該考慮從頭到尾的過程,並為rename
或readdir
函數未提供的所有其他難題編寫代碼。
例如,如果計划傳遞新的目錄名 ,則需要驗證您也打算移動文件的目錄確實存在(或者您需要創建它)。 您如何測試新目錄的存在? 您還需要確定並驗證將文件rename
為的新目錄的格式。 它是否包含尾隨'/'
? 如果可以,該如何處理?
如果只想移動具有特定擴展名的文件,則必須開發一種方法來檢查並從readdir
返回的每個文件名中獲取擴展名。 獲得當前文件的擴展名后,如何將其與目標擴展名進行比較?
最后,如何將打算將匹配文件移至的目錄名與當前文件名結合起來,以創建將文件移至的完整路徑? 所有這些都是您需要提供的一些代碼,以便能夠將文件從一個目錄移動到另一個目錄。 難做嗎? 不會。這很容易,但是您必須在該級別進行仔細考慮,並提供最少的驗證以確定要移動的任何單個文件的成功/失敗。
因為我了解您需要幫助,而不是繼續研究如何創建每個難題,並且有一個合理的“ go-by”可以幫助您將難題的各個組成部分牢記在心,但下面是一個簡短的例子,可以解決您的問題。 以下內容將要搜索的目錄作為第一個參數,將搜索的擴展名作為第二個參數,並將所有匹配文件移動到的相對或絕對路徑名作為第三個參數(默認文件名是.
(搜索當前目錄))。帶有"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
仔細看一下,如果您有任何問題,請告訴我。 它本身並不是一件容易的事,但是要提供一個合理而穩健的舉動有很多考慮(可以添加更多驗證,這只是一個最小的示例)。
opendir()只是第一個函數。 它為您提供了可以使用的DIR結構,僅此而已。 要獲取文件列表,您需要一個循環來運行readdir()。 請參閱以獲取完整的文檔:
https://www.gnu.org/software/libc/manual/html_node/Accessing-Directories.html#Accessing-Directories
但是,如果可以的話,使用glob()比opendir()容易得多。 看到:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.