dirent--文件以及文件夹相关操作(跨平台)

来源:互联网 发布:安卓版看图软件 编辑:程序博客网 时间:2024/05/16 07:25

windows客户端开发–文件以及文件夹相关操作(windows api)
一文中,主要使用了一些windows api实现文件以及文件夹的相关操作。

c++语言本身不提供文件相关操作,我们也可以使用boost库完成我们想要的功能。

但是为了仅仅一个小功能,引入boost库,似乎有点小题大做吧,那今天就介绍一种“跨平台”的文件操作,dirent。

这里所谓的“跨平台”其实是个伪命题,不是真正意义上的。

let us go!!!

初识dirent

是POSIX.1标准定义的unix类目录操作的头文件,包含了许多UNIX系统服务的函数原型,例如opendir函数、readdir函数.

看到上面的描述,你会理解我所说的用引号引起来的“跨平台”了。

在windows平台上同样可以使用:
https://github.com/tronkko/dirent/blob/master/include/dirent.h

只是简单的包含这个头文件dirent.h就可以了,因为这个文件只有八百多行,在博客的最后面,我将会贴上这个源码。

熟悉dirent

dirent结构体:

    struct dirent {        long d_ino;     /* Always zero */        unsigned short d_reclen;  /* Structure size */        size_t d_namlen;    /* Length of name without \0 */        int d_type;   /* File type */        char d_name[PATH_MAX];     /* File name */    };    typedef struct dirent dirent;

DIR:
A type representing a directory stream.

struct DIR {        struct dirent ent;        struct _WDIR *wdirp;    };    typedef struct DIR DIR;

一些函数:

int closedir(DIR *);DIR *opendir(const char *);struct dirent *readdir(DIR *);int readdir_r(DIR *, struct dirent *, struct dirent **);void rewinddir(DIR *);void seekdir(DIR *, long int);long int telldir(DIR *);

使用dirent

删除文件夹下所有文件:

DIR *foder = opendir(file_path_to_delete.c_str());    struct dirent *next_file;    char filepath[256];    while ((next_file = readdir(foder)) != NULL)    {        // build the path for each file in the folder        sprintf(filepath, "%s/%s", course_path.c_str(), next_file->d_name);        remove(filepath);    }

注意:
路径要以’/’结尾:

file_path_to_delete += "\/";

判断目录是否存在:

 DIR *mydir = NULL;      if((mydir= opendir(dir))==NULL)//判断目录       {        int ret = mkdir(dir, MODE);//创建目录        if (ret != 0)        {            return -1;        }        printf("%s created sucess!/n", dir);      }  

判断是文件夹还是文件:

unsigned char isFile =0x8;DIR Dir;struct dirent *DirEntry;Dir = opendir("c:/test/")while(Dir=readdir(Dir)){   if ( DirEntry->d_type == isFile)   {    cout <<"Found a File : " << DirEntry->d_name << endl;   }}

==========================================================华丽的分割线============================================================

//dirent.h

/** dirent.h - dirent API for Microsoft Visual Studio** Copyright (C) 2006-2012 Toni Ronkko** Permission is hereby granted, free of charge, to any person obtaining* a copy of this software and associated documentation files (the* ``Software''), to deal in the Software without restriction, including* without limitation the rights to use, copy, modify, merge, publish,* distribute, sublicense, and/or sell copies of the Software, and to* permit persons to whom the Software is furnished to do so, subject to* the following conditions:** The above copyright notice and this permission notice shall be included* in all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.* IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR* OTHER DEALINGS IN THE SOFTWARE.** $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $*/#ifndef DIRENT_H#define DIRENT_H/** Define architecture flags so we don't need to include windows.h.* Avoiding windows.h makes it simpler to use windows sockets in conjunction* with dirent.h.*/#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)#   define _X86_#endif#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64)#define _AMD64_#endif#include <stdio.h>#include <stdarg.h>#include <windef.h>#include <winbase.h>#include <wchar.h>#include <string.h>#include <stdlib.h>#include <malloc.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>/* Indicates that d_type field is available in dirent structure */#define _DIRENT_HAVE_D_TYPE/* Indicates that d_namlen field is available in dirent structure */#define _DIRENT_HAVE_D_NAMLEN/* Entries missing from MSVC 6.0 */#if !defined(FILE_ATTRIBUTE_DEVICE)#   define FILE_ATTRIBUTE_DEVICE 0x40#endif/* File type and permission flags for stat() */#if !defined(S_IFMT)#   define S_IFMT   _S_IFMT                     /* File type mask */#endif#if !defined(S_IFDIR)#   define S_IFDIR  _S_IFDIR                    /* Directory */#endif#if !defined(S_IFCHR)#   define S_IFCHR  _S_IFCHR                    /* Character device */#endif#if !defined(S_IFFIFO)#   define S_IFFIFO _S_IFFIFO                   /* Pipe */#endif#if !defined(S_IFREG)#   define S_IFREG  _S_IFREG                    /* Regular file */#endif#if !defined(S_IREAD)#   define S_IREAD  _S_IREAD                    /* Read permission */#endif#if !defined(S_IWRITE)#   define S_IWRITE _S_IWRITE                   /* Write permission */#endif#if !defined(S_IEXEC)#   define S_IEXEC  _S_IEXEC                    /* Execute permission */#endif#if !defined(S_IFIFO)#   define S_IFIFO _S_IFIFO                     /* Pipe */#endif#if !defined(S_IFBLK)#   define S_IFBLK   0                          /* Block device */#endif#if !defined(S_IFLNK)#   define S_IFLNK   0                          /* Link */#endif#if !defined(S_IFSOCK)#   define S_IFSOCK  0                          /* Socket */#endif#if defined(_MSC_VER)#   define S_IRUSR  S_IREAD                     /* Read user */#   define S_IWUSR  S_IWRITE                    /* Write user */#   define S_IXUSR  0                           /* Execute user */#   define S_IRGRP  0                           /* Read group */#   define S_IWGRP  0                           /* Write group */#   define S_IXGRP  0                           /* Execute group */#   define S_IROTH  0                           /* Read others */#   define S_IWOTH  0                           /* Write others */#   define S_IXOTH  0                           /* Execute others */#endif/* Maximum length of file name */#if !defined(PATH_MAX)#   define PATH_MAX MAX_PATH#endif#if !defined(FILENAME_MAX)#   define FILENAME_MAX MAX_PATH#endif#if !defined(NAME_MAX)#   define NAME_MAX FILENAME_MAX#endif/* File type flags for d_type */#define DT_UNKNOWN  0#define DT_REG      S_IFREG#define DT_DIR      S_IFDIR#define DT_FIFO     S_IFIFO#define DT_SOCK     S_IFSOCK#define DT_CHR      S_IFCHR#define DT_BLK      S_IFBLK#define DT_LNK      S_IFLNK/* Macros for converting between st_mode and d_type */#define IFTODT(mode) ((mode) & S_IFMT)#define DTTOIF(type) (type)/** File type macros.  Note that block devices, sockets and links cannot be* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are* only defined for compatibility.  These macros should always return false* on Windows.*/#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)#define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)#define S_ISLNK(mode)  (((mode) & S_IFMT) == S_IFLNK)#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)#define S_ISCHR(mode)  (((mode) & S_IFMT) == S_IFCHR)#define S_ISBLK(mode)  (((mode) & S_IFMT) == S_IFBLK)/* Return the exact length of d_namlen without zero terminator */#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)/* Return number of bytes needed to store d_namlen */#define _D_ALLOC_NAMLEN(p) (PATH_MAX)#ifdef __cplusplusextern "C" {#endif    /* Wide-character version */    struct _wdirent {        long d_ino;                                 /* Always zero */        unsigned short d_reclen;                    /* Structure size */        size_t d_namlen;                            /* Length of name without \0 */        int d_type;                                 /* File type */        wchar_t d_name[PATH_MAX];                   /* File name */    };    typedef struct _wdirent _wdirent;    struct _WDIR {        struct _wdirent ent;                        /* Current directory entry */        WIN32_FIND_DATAW data;                      /* Private file data */        int cached;                                 /* True if data is valid */        HANDLE handle;                              /* Win32 search handle */        wchar_t *patt;                              /* Initial directory name */    };    typedef struct _WDIR _WDIR;    static _WDIR *_wopendir(const wchar_t *dirname);    static struct _wdirent *_wreaddir(_WDIR *dirp);    static int _wclosedir(_WDIR *dirp);    static void _wrewinddir(_WDIR* dirp);    /* For compatibility with Symbian */#define wdirent _wdirent#define WDIR _WDIR#define wopendir _wopendir#define wreaddir _wreaddir#define wclosedir _wclosedir#define wrewinddir _wrewinddir    /* Multi-byte character versions */    struct dirent {        long d_ino;                                 /* Always zero */        unsigned short d_reclen;                    /* Structure size */        size_t d_namlen;                            /* Length of name without \0 */        int d_type;                                 /* File type */        char d_name[PATH_MAX];                      /* File name */    };    typedef struct dirent dirent;    struct DIR {        struct dirent ent;        struct _WDIR *wdirp;    };    typedef struct DIR DIR;    static DIR *opendir(const char *dirname);    static struct dirent *readdir(DIR *dirp);    static int closedir(DIR *dirp);    static void rewinddir(DIR* dirp);    /* Internal utility functions */    static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);    static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);    static int dirent_mbstowcs_s(        size_t *pReturnValue,        wchar_t *wcstr,        size_t sizeInWords,        const char *mbstr,        size_t count);    static int dirent_wcstombs_s(        size_t *pReturnValue,        char *mbstr,        size_t sizeInBytes,        const wchar_t *wcstr,        size_t count);    static void dirent_set_errno(int error);    /*    * Open directory stream DIRNAME for read and return a pointer to the    * internal working area that is used to retrieve individual directory    * entries.    */    static _WDIR*        _wopendir(        const wchar_t *dirname)    {        _WDIR *dirp = NULL;        int error;        /* Must have directory name */        if (dirname == NULL || dirname[0] == '\0') {            dirent_set_errno(ENOENT);            return NULL;        }        /* Allocate new _WDIR structure */        dirp = (_WDIR*)malloc(sizeof(struct _WDIR));        if (dirp != NULL) {            DWORD n;            /* Reset _WDIR structure */            dirp->handle = INVALID_HANDLE_VALUE;            dirp->patt = NULL;            dirp->cached = 0;            /* Compute the length of full path plus zero terminator */            n = GetFullPathNameW(dirname, 0, NULL, NULL);            /* Allocate room for absolute directory name and search pattern */            dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16);            if (dirp->patt) {                /*                * Convert relative directory name to an absolute one.  This                * allows rewinddir() to function correctly even when current                * working directory is changed between opendir() and rewinddir().                */                n = GetFullPathNameW(dirname, n, dirp->patt, NULL);                if (n > 0) {                    wchar_t *p;                    /* Append search pattern \* to the directory name */                    p = dirp->patt + n;                    if (dirp->patt < p) {                        switch (p[-1]) {                        case '\\':                        case '/':                        case ':':                            /* Directory ends in path separator, e.g. c:\temp\ */                            /*NOP*/;                            break;                        default:                            /* Directory name doesn't end in path separator */                            *p++ = '\\';                        }                    }                    *p++ = '*';                    *p = '\0';                    /* Open directory stream and retrieve the first entry */                    if (dirent_first(dirp)) {                        /* Directory stream opened successfully */                        error = 0;                    }                    else {                        /* Cannot retrieve first entry */                        error = 1;                        dirent_set_errno(ENOENT);                    }                }                else {                    /* Cannot retrieve full path name */                    dirent_set_errno(ENOENT);                    error = 1;                }            }            else {                /* Cannot allocate memory for search pattern */                error = 1;            }        }        else {            /* Cannot allocate _WDIR structure */            error = 1;        }        /* Clean up in case of error */        if (error  &&  dirp) {            _wclosedir(dirp);            dirp = NULL;        }        return dirp;    }    /*    * Read next directory entry.  The directory entry is returned in dirent    * structure in the d_name field.  Individual directory entries returned by    * this function include regular files, sub-directories, pseudo-directories    * "." and ".." as well as volume labels, hidden files and system files.    */    static struct _wdirent*        _wreaddir(        _WDIR *dirp)    {        WIN32_FIND_DATAW *datap;        struct _wdirent *entp;        /* Read next directory entry */        datap = dirent_next(dirp);        if (datap) {            size_t n;            DWORD attr;            /* Pointer to directory entry to return */            entp = &dirp->ent;            /*            * Copy file name as wide-character string.  If the file name is too            * long to fit in to the destination buffer, then truncate file name            * to PATH_MAX characters and zero-terminate the buffer.            */            n = 0;            while (n + 1 < PATH_MAX  &&  datap->cFileName[n] != 0) {                entp->d_name[n] = datap->cFileName[n];                n++;            }            dirp->ent.d_name[n] = 0;            /* Length of file name excluding zero terminator */            entp->d_namlen = n;            /* File type */            attr = datap->dwFileAttributes;            if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {                entp->d_type = DT_CHR;            }            else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {                entp->d_type = DT_DIR;            }            else {                entp->d_type = DT_REG;            }            /* Reset dummy fields */            entp->d_ino = 0;            entp->d_reclen = sizeof(struct _wdirent);        }        else {            /* Last directory entry read */            entp = NULL;        }        return entp;    }    /*    * Close directory stream opened by opendir() function.  This invalidates the    * DIR structure as well as any directory entry read previously by    * _wreaddir().    */    static int        _wclosedir(        _WDIR *dirp)    {        int ok;        if (dirp) {            /* Release search handle */            if (dirp->handle != INVALID_HANDLE_VALUE) {                FindClose(dirp->handle);                dirp->handle = INVALID_HANDLE_VALUE;            }            /* Release search pattern */            if (dirp->patt) {                free(dirp->patt);                dirp->patt = NULL;            }            /* Release directory structure */            free(dirp);            ok = /*success*/0;        }        else {            /* Invalid directory stream */            dirent_set_errno(EBADF);            ok = /*failure*/-1;        }        return ok;    }    /*    * Rewind directory stream such that _wreaddir() returns the very first    * file name again.    */    static void        _wrewinddir(        _WDIR* dirp)    {        if (dirp) {            /* Release existing search handle */            if (dirp->handle != INVALID_HANDLE_VALUE) {                FindClose(dirp->handle);            }            /* Open new search handle */            dirent_first(dirp);        }    }    /* Get first directory entry (internal) */    static WIN32_FIND_DATAW*        dirent_first(        _WDIR *dirp)    {        WIN32_FIND_DATAW *datap;        /* Open directory and retrieve the first entry */        dirp->handle = FindFirstFileW(dirp->patt, &dirp->data);        if (dirp->handle != INVALID_HANDLE_VALUE) {            /* a directory entry is now waiting in memory */            datap = &dirp->data;            dirp->cached = 1;        }        else {            /* Failed to re-open directory: no directory entry in memory */            dirp->cached = 0;            datap = NULL;        }        return datap;    }    /* Get next directory entry (internal) */    static WIN32_FIND_DATAW*        dirent_next(        _WDIR *dirp)    {        WIN32_FIND_DATAW *p;        /* Get next directory entry */        if (dirp->cached != 0) {            /* A valid directory entry already in memory */            p = &dirp->data;            dirp->cached = 0;        }        else if (dirp->handle != INVALID_HANDLE_VALUE) {            /* Get the next directory entry from stream */            if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {                /* Got a file */                p = &dirp->data;            }            else {                /* The very last entry has been processed or an error occured */                FindClose(dirp->handle);                dirp->handle = INVALID_HANDLE_VALUE;                p = NULL;            }        }        else {            /* End of directory stream reached */            p = NULL;        }        return p;    }    /*    * Open directory stream using plain old C-string.    */    static DIR*        opendir(        const char *dirname)    {        struct DIR *dirp;        int error;        /* Must have directory name */        if (dirname == NULL || dirname[0] == '\0') {            dirent_set_errno(ENOENT);            return NULL;        }        /* Allocate memory for DIR structure */        dirp = (DIR*)malloc(sizeof(struct DIR));        if (dirp) {            wchar_t wname[PATH_MAX];            size_t n;            /* Convert directory name to wide-character string */            error = dirent_mbstowcs_s(&n, wname, PATH_MAX, dirname, PATH_MAX);            if (!error) {                /* Open directory stream using wide-character name */                dirp->wdirp = _wopendir(wname);                if (dirp->wdirp) {                    /* Directory stream opened */                    error = 0;                }                else {                    /* Failed to open directory stream */                    error = 1;                }            }            else {                /*                * Cannot convert file name to wide-character string.  This                * occurs if the string contains invalid multi-byte sequences or                * the output buffer is too small to contain the resulting                * string.                */                error = 1;            }        }        else {            /* Cannot allocate DIR structure */            error = 1;        }        /* Clean up in case of error */        if (error  &&  dirp) {            free(dirp);            dirp = NULL;        }        return dirp;    }    /*    * Read next directory entry.    *    * When working with text consoles, please note that file names returned by    * readdir() are represented in the default ANSI code page while any output to    * console is typically formatted on another code page.  Thus, non-ASCII    * characters in file names will not usually display correctly on console.  The    * problem can be fixed in two ways: (1) change the character set of console    * to 1252 using chcp utility and use Lucida Console font, or (2) use    * _cprintf function when writing to console.  The _cprinf() will re-encode    * ANSI strings to the console code page so many non-ASCII characters will    * display correcly.    */    static struct dirent*        readdir(        DIR *dirp)    {        WIN32_FIND_DATAW *datap;        struct dirent *entp;        /* Read next directory entry */        datap = dirent_next(dirp->wdirp);        if (datap) {            size_t n;            int error;            /* Attempt to convert file name to multi-byte string */            error = dirent_wcstombs_s(                &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);            /*            * If the file name cannot be represented by a multi-byte string,            * then attempt to use old 8+3 file name.  This allows traditional            * Unix-code to access some file names despite of unicode            * characters, although file names may seem unfamiliar to the user.            *            * Be ware that the code below cannot come up with a short file            * name unless the file system provides one.  At least            * VirtualBox shared folders fail to do this.            */            if (error  &&  datap->cAlternateFileName[0] != '\0') {                error = dirent_wcstombs_s(                    &n, dirp->ent.d_name, PATH_MAX,                    datap->cAlternateFileName, PATH_MAX);            }            if (!error) {                DWORD attr;                /* Initialize directory entry for return */                entp = &dirp->ent;                /* Length of file name excluding zero terminator */                entp->d_namlen = n - 1;                /* File attributes */                attr = datap->dwFileAttributes;                if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {                    entp->d_type = DT_CHR;                }                else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {                    entp->d_type = DT_DIR;                }                else {                    entp->d_type = DT_REG;                }                /* Reset dummy fields */                entp->d_ino = 0;                entp->d_reclen = sizeof(struct dirent);            }            else {                /*                * Cannot convert file name to multi-byte string so construct                * an errornous directory entry and return that.  Note that                * we cannot return NULL as that would stop the processing                * of directory entries completely.                */                entp = &dirp->ent;                entp->d_name[0] = '?';                entp->d_name[1] = '\0';                entp->d_namlen = 1;                entp->d_type = DT_UNKNOWN;                entp->d_ino = 0;                entp->d_reclen = 0;            }        }        else {            /* No more directory entries */            entp = NULL;        }        return entp;    }    /*    * Close directory stream.    */    static int        closedir(        DIR *dirp)    {        int ok;        if (dirp) {            /* Close wide-character directory stream */            ok = _wclosedir(dirp->wdirp);            dirp->wdirp = NULL;            /* Release multi-byte character version */            free(dirp);        }        else {            /* Invalid directory stream */            dirent_set_errno(EBADF);            ok = /*failure*/-1;        }        return ok;    }    /*    * Rewind directory stream to beginning.    */    static void        rewinddir(        DIR* dirp)    {        /* Rewind wide-character string directory stream */        _wrewinddir(dirp->wdirp);    }    /* Convert multi-byte string to wide character string */    static int        dirent_mbstowcs_s(        size_t *pReturnValue,        wchar_t *wcstr,        size_t sizeInWords,        const char *mbstr,        size_t count)    {        int error;#if defined(_MSC_VER)  &&  _MSC_VER >= 1400        /* Microsoft Visual Studio 2005 or later */        error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count);#else        /* Older Visual Studio or non-Microsoft compiler */        size_t n;        /* Convert to wide-character string (or count characters) */        n = mbstowcs(wcstr, mbstr, sizeInWords);        if (!wcstr || n < count) {            /* Zero-terminate output buffer */            if (wcstr  &&  sizeInWords) {                if (n >= sizeInWords) {                    n = sizeInWords - 1;                }                wcstr[n] = 0;            }            /* Length of resuting multi-byte string WITH zero terminator */            if (pReturnValue) {                *pReturnValue = n + 1;            }            /* Success */            error = 0;        }        else {            /* Could not convert string */            error = 1;        }#endif        return error;    }    /* Convert wide-character string to multi-byte string */    static int        dirent_wcstombs_s(        size_t *pReturnValue,        char *mbstr,        size_t sizeInBytes, /* max size of mbstr */        const wchar_t *wcstr,        size_t count)    {        int error;#if defined(_MSC_VER)  &&  _MSC_VER >= 1400        /* Microsoft Visual Studio 2005 or later */        error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count);#else        /* Older Visual Studio or non-Microsoft compiler */        size_t n;        /* Convert to multi-byte string (or count the number of bytes needed) */        n = wcstombs(mbstr, wcstr, sizeInBytes);        if (!mbstr || n < count) {            /* Zero-terminate output buffer */            if (mbstr  &&  sizeInBytes) {                if (n >= sizeInBytes) {                    n = sizeInBytes - 1;                }                mbstr[n] = '\0';            }            /* Lenght of resulting multi-bytes string WITH zero-terminator */            if (pReturnValue) {                *pReturnValue = n + 1;            }            /* Success */            error = 0;        }        else {            /* Cannot convert string */            error = 1;        }#endif        return error;    }    /* Set errno variable */    static void        dirent_set_errno(        int error)    {#if defined(_MSC_VER)  &&  _MSC_VER >= 1400        /* Microsoft Visual Studio 2005 and later */        _set_errno(error);#else        /* Non-Microsoft compiler or older Microsoft compiler */        errno = error;#endif    }#ifdef __cplusplus}#endif#endif /*DIRENT_H*/
5 0