簡體   English   中英

將文件移動到其他Linux目錄

[英]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庫函數通常只能做一件事,而只能做一件事。 程序員應該考慮從頭到尾的過程,並為renamereaddir函數未提供的所有其他難題編寫代碼。

例如,如果計划傳遞新的目錄名 ,則需要驗證您也打算移動文件的目錄確實存在(或者您需要創建它)。 您如何測試新目錄的存在? 您還需要確定並驗證將文件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()容易得多。 看到:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM