linux系統程式設計之檔案與IO(四):目錄訪問相關係統呼叫

mickole發表於2013-07-10

1. 目錄操作相關的系統呼叫
    1.1 mkdir和rmdir系統呼叫
    1.1.1 例項
    1.2 chdir, getcwd系統呼叫
    1.2.1 例項
    1.3 opendir, closedir, readdir,
    1.3.1 例項:遞迴便利目錄

1. 目錄操作相關的系統呼叫

 

    1.1 mkdir和rmdir系統呼叫

 

[code]
filename: mk_rm_dir.c
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);
return:
    S    0
    F    -1
note:
    mode許可權至少要有執行許可權。
[/code]
[code]
#include <unistd.h>
int rmdir(const char *pathname);
return:
    S    0
    F    -1
note:
    pathname目錄必須是空目錄。

    1.1.1 例項


#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <assert.h>
#define MODE    (S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH)
int main(int argc, char *argv[])
{
    char    *pname;
    assert(argc == 2);
    pname = argv[1];
    assert(mkdir(pname, MODE) == 0);
    printf("create %s successful!\n", pname);
    assert(rmdir(pname) == 0);
    printf("rm %s\n", pname);
    return 0;
}


    測試:

[qtlldr@qtldr editing]$ ./mk_rm_dir  testdir
create testdir successful!
rm testdir
[qtlldr@qtldr editing]$ 
 

   1.2 chdir, getcwd系統呼叫



#include <unistd.h>
int chdir(const char *pathname);
return:
    S    0
    F    -1

#include <unistd.h>
char *getpwd(char *buf, size_t size);
return:
    S    buf
    F    NULL

    buf是緩衝地址,size是buf的長度。該緩衝必須有足夠的長度以容納絕對路徑名加上一個null終止符。

    1.2.1 例項


[code]
filename:ch_get_dir.c

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define BUFSIZE    (50)
int main(void)
{
    char buf[BUFSIZE];
    memset((void *)buf, '\0', sizeof buf);
    assert(chdir("/tmp") == 0);
    printf("chdir to /tmp successful\n");
    assert(getcwd(buf, BUFSIZE) != NULL);
    printf("now the directory is %s\n", buf);
    return 0;
}


    測試:

[qtlldr@qtldr editing]$ ./ch_get_dir
chdir to /tmp successful
now the directory is /tmp
[qtlldr@qtldr editing]$ 

    1.3 opendir, closedir, readdir,



#include <sys/type.s>
#include <dirent.h>
DIR *opendir(const char *dirname);
return:
    S    DIR指標
    F    NULL
note:
    DIR是一種目錄結構,類似FILE。

#include <sys/types.h>
#include <dirent.h>
struct dirent *readir(DIR *dirp);
return:
    S    一個指向儲存目錄流下一個目錄項的dirent指標
    F    NULL
note:
    struct dirent {
        char    d_name[NAME + 1]; /* \0結尾的檔名 */
    }
    到達目錄尾或出錯返回NULL,但是到達目錄尾不會設定errno,出錯則設定。
    如果在readir的同時有其他程式在目錄中建立或者刪除檔案愛你,readdir不保證能列處該目錄中所有檔案。

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
return:
    S    0
    F    -1

    1.3.1 例項:遞迴便利目錄



filename:help.txt 幫助文件
            本程式只為學習linux目錄操作而寫
printdir
    輸出目錄檔案或者統計目錄中的檔案數目
語法:
    printdir [option] <files...>
選項:
    -l
        輸出目錄下的檔名
    -c
        統計目錄下的檔案
    -d n
        指定最大層次,最大為30
預設行為:
    如果沒有指定選項,那麼只輸出該目錄下的檔名
BUG:
    -l與 -c選項不能同時使用,如果同時使用統計出錯。(以後會修正)

            本程式只為學習linux目錄操作而寫

filename:printdir.c

#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INDENT_DEPTH    (4) /* 列舉檔案時的縮排數 */
#define DEPTH_MAX (30)    /* 遞迴便利的最大層次 */
#define HELPFILE ("help.txt")
typedef int count_t;
struct nfiletype {
    count_t ndir;
    count_t nreg;
    count_t nchr;
    count_t    nfifo;
    count_t    nsock;
    count_t nchar;
    count_t nblock;
    count_t    nlink;
    count_t ntotol;
    count_t nunknow;
};/*記錄各個型別檔案的數目*/
int    DEPTH = 20; /* 遞迴層級限制 */
int idepth_count = 1;
int idepth_print = 1;

static struct nfiletype *count_files(const char *pathname,
            struct nfiletype *nfile);

static void  printdir(const char *pathname, int indent);
int main(int argc, char **argv)
{
    int opt;
    int    depth_opt;
    int    count_flag = 0;
    int    print_flag = 0;
    char *parg = NULL;
    struct nfiletype nfiles = {0};
    int    fd_help;
    char buf_help[BUFSIZ];
    int nread_help;
    char *filename_help = HELPFILE;
    while ((opt = getopt(argc, argv, "lhd:c")) != -1) {
        switch (opt) {
            case 'l':
                print_flag = 1;
                break;
            case 'c':
                count_flag = 1;
                break;
            case 'd':
                depth_opt = strtol(optarg, NULL, 10);
                DEPTH = depth_opt <= DEPTH_MAX ? depth_opt: DEPTH;
                break;
            case ':':
                printf("option needs a value\n");
                break;
            case '?':
                printf("unknown option :%c\n", optopt);
                break;
            case 'h':
                fd_help = open(filename_help, O_RDONLY);
                if (fd_help != -1) {
                    while ((nread_help = read(fd_help, buf_help, BUFSIZ)) > 0) {
                        write(1, buf_help, nread_help);
                    }
                    close(fd_help);
                } else {
                    fprintf(stderr, "open %s failed!\n", filename_help);
                }
                return 0;
        }
    }
    /* 如果沒有選項,那麼預設是列印目錄 */
    if (!print_flag && !count_flag)
        print_flag = 1;
    for( ; optind < argc; optind++) {
        parg = argv[optind];
        if (print_flag) {
            //printf("DEBUG-- printdir --%s\n", parg);
            printdir(parg, 4);
        }
        if (count_flag) {
            memset((void *)&nfiles, '\0', sizeof nfiles);
            //printf("DEBUG-- count_files--%s\n", parg);
            count_files(parg, &nfiles);
            printf("In the %s there are :\n", parg);
            printf("     directory %d\n", nfiles.ndir);
            printf("     regular file %d\n", nfiles.nreg);
            printf("     specal character file %d\n", nfiles.nchr);
            printf("     special block file %d\n", nfiles.nblock);
            printf("     fifo file %d\n", nfiles.nfifo);
            printf("     sock file %d\n", nfiles.nsock);
            printf("     link file %d\n", nfiles.nlink);
            printf("     unknown file %d\n", nfiles.nunknow);
            printf("Total %d\n", nfiles.ntotol);
        }
    }
    return 0;
}
/*
 *function: 對該目錄下的檔案型別進行統計
 * input arg:
 *        pathname:目錄名指標
 *        nfile:記錄檔案型別數目的結構體指標
 * return:
 *        記錄檔案型別數目的結構體指標
 */

static struct nfiletype *count_files(const char *pathname,
            struct nfiletype *nfile)
{
    DIR *dp;
    struct dirent *entry;
    struct stat    statbuf;
    //printf("DEBUG-- in count_files -- %s\n", pathname);
    /* 層次控制 */    
    if (idepth_count > DEPTH)
        return NULL;
    idepth_count++;
    if ((dp = opendir(pathname)) == NULL) {
        fprintf(stderr, "can not open %s\n", pathname);
        return NULL;
    }
    chdir(pathname);
    while ((entry = readdir(dp)) != NULL) {
        /* 跳過 . 和 .. */
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            continue;
        /* 取得檔案資訊 */
        if (lstat(entry->d_name, &statbuf) == -1) {
            fprintf(stderr, "can not test the %s's type\n", entry->d_name);
            return NULL;
        }
        /* 統計檔案數目 */
        if (S_ISDIR(statbuf.st_mode)) { /* 是目錄就遞迴吧 */
            //printf("DEBUG -- directory %s\n", entry->d_name);
            count_files(entry->d_name, nfile);
            nfile->ndir++;
        }
        else if (S_ISREG(statbuf.st_mode)) {
            //printf("DEBUG -- regular file %s\n", entry->d_name);
            nfile->nreg++;
        }
        else if (S_ISCHR(statbuf.st_mode))
            nfile->nchr++;
        else if (S_ISBLK(statbuf.st_mode))
            nfile->nblock++;
        else if (S_ISLNK(statbuf.st_mode))
            nfile->nlink++;
        else if (S_ISFIFO(statbuf.st_mode))
            nfile->nfifo++;
        else if (S_ISSOCK(statbuf.st_mode))
            nfile->nsock++;
        else nfile->nunknow++;
        nfile->ntotol++;
    }
    chdir("..");
    closedir(dp);
    return nfile;
 }
 /*
nblock; *function:列出目錄中的檔案
nlink;  *input arg:
ntotol; *        pathname: 目錄名
 *return:
 *        void
 */

static void   printdir(const char *pathname, int indent)
{
    DIR *dp;
    struct dirent *entry;
    struct stat    statbuf;
    /* 層次控制 */    
    if (idepth_print > DEPTH)
        return ;
    idepth_print++;
    if ((dp = opendir(pathname)) == NULL) {
        fprintf(stderr, "can not open %s\n", pathname);
        return ;
    }
    chdir(pathname);
    while ((entry = readdir(dp)) != NULL) {
        /* 跳過 . 和 .. */
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            continue;
        if (lstat(entry->d_name, &statbuf) == -1) {
            fprintf(stderr, "can not test the %s's type\n", entry->d_name);
            return ;
        }
        if (S_ISDIR(statbuf.st_mode)) { /* 是目錄就遞迴吧 */
            printf("%*s%s/\n", indent," ",  entry->d_name);
            printdir(entry->d_name, indent + INDENT_DEPTH);
        }
        else {
            printf("%*s%s\n", indent," ", entry->d_name);
            }
    }
    chdir("..");
    closedir(dp);
}


注:本文轉自:http://blog.chinaunix.net/uid-26242642-id-2779802.html

相關文章