Linux C语言 36-文件处理补充

Linux C语言 36-文件处理补充

本节关键字:C语言 文件操作,文件处理,文件创建,文件信息,文件删除,目录创建,目录信息,目录遍历,目录递归遍历
相关C库函数:access、mkdir、opendir、chdir、readdir、closedir、rm、stat等

声明:时间有限,目前仅将相关库函数记录下来,后期慢慢完善用法及例程,感兴趣的小伙伴可以先关注,有更新就会提醒哦~

判断文件是否存在

#include 
int access(const char *pathname, int mode);
/**
@brief 判断指定的文件或目录是否存在
@param pathname 目标文件或目录的绝对路径
@param mode 判断模式 F_OK(存在)、R_OK(可读)、W_OK(可写)、X_OK(可执行)
@return 成功返回0,失败返回-1

错误码error:
EACCES           请求的对文件的访问将被拒绝,或者路径前缀中某个目录的搜索权限被拒绝的路径名
ELOOP            解析路径名时遇到过多符号链接
ENAMETOOLONG     路径名太
ENOENT           路径名的组件不存在或是悬挂的符号链接
ENOTDIR          在路径名中用作目录的组件实际上不是目录
EROFS            已请求对只读文件系统上的文件授予写入权限
EFAULT           pathname指向可访问的地址空间之外
EINVAL           未正确指定模式
EIO              出现I/O错误
ENOMEM           可用的内核内存不足
ETXTBSY          请求对正在执行的可执行文件进行写访问
*/
void main(void)
{
    char pathname[] = "/etc/my.cnf";
    if (access(pathname, F_OK) == 0)
        printf("F_OK\n");
    
    if (access(pathname, R_OK) == 0)
        printf("R_OK\n");
    
    if (access(pathname, W_OK) == 0)
        printf("W_OK\n");
    
    if (access(pathname, X_OK) == 0)
        printf("X_OK\n");
}

创建目录

#include 
#include 
int mkdir(const char *pathname, mode_t mode);
/**
@brief 创建一个名为pathname的目录,一次只能创建一层目录
@param pathname 目录的绝对路径
@param mode 权限umask,例如:0777
@return 成功返回0,失败返回-1

错误码error:
EACCES          父目录不允许对进程进行写入权限,或者路径名中的某个目录不允许搜索
EEXIST          路径名已存在(不一定是目录)。这包括路径名是一个符号链接的情况
EFAULT          路径名指向您的可访问地址空间之外
ELOOP           解析路径名时遇到过多符号链接
ENAMETOOLONG    路径名太长
ENOENT          路径名中的目录组件不存在或是悬挂的符号链接
ENOMEM          可用内核内存不足
ENOSPC          包含路径名的设备没有空间容纳新目录
ENOSPC          无法创建新目录,因为用户的磁盘配额已用完
ENOTDIR         在路径名中用作目录的组件实际上不是目录
EPERM           包含路径名的文件系统不支持创建目录
EROFS           路径名是指只读文件系统上的文件
*/
void main(void)
{
    char pathname[] = "/home/user/mkdir_test";
    if (mkdir(pathname, 0777) == 0)
        printf("mkdir %s\n", pathname);
}

获取目录的文件描述符

#include 
#include 

struct __dirstream   
{   
    void *__fd;
    char *__data;    
    int __entry_data;    
    char *__ptr;    
    int __entry_ptr;    
    size_t __allocation;    
    size_t __size;    
    __libc_lock_define (, __lock)    
};   
typedef struct __dirstream DIR;

int dirfd(DIR *dirp);
/**
@brief 获取参数dirp指向的目录流文件描述符,返回的文件描述符可以使用closedir()关闭
@param dirp 指向目录流的指针
@return 成功返回非负文件描述符,失败返回-1
*/

打开目录

#include 
#include 
DIR *opendir(const char *name);
/**
@brief 打开与目录名对应的目录流,流处于目录中的第一个条目处
@param name 目录名称
@return 成功返回指向该目录流的指针,失败返回NULL
*/
DIR *fdopendir(int fd);
/**
@brief 打开与文件描述符对应的目录流,流处于目录中的第一个条目处
@param fd 目录文件描述符
@return 成功返回指向该目录流的指针,失败返回NULL
*/

读取/遍历目录

#include 
struct dirent 
{
   ino_t          d_ino;       /* inode number 索引节点号 */
   off_t          d_off;       /* offset to the next dirent 偏移到下一个条目 */
   unsigned short d_reclen;    /* length of this record 记录的长度 */
   unsigned char  d_type;      /* type of file; not supported by all file system types 文件类型 */
   char           d_name[256]; /* filename 文件名 */
};
struct dirent *readdir(DIR *dirp);
/**
@brief 读取目录流的当前条目信息,并返回下一个目录条目
@param dirp 指向目录流的指针
@return 成功返回指向该目录流下一个目录条目的指针,到达目录末尾或发生错误时返回NULL
*/
int readdir(unsigned int fd, struct old_linux_dirent *dirp, unsigned int count);
/**
@brief 读取目录流,旧版本函数,此处不详细描述了
*/
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
/**
@brief 读取目录流的当前条目信息,readdir的可重入版本
@param dirp 指向目录流的指针
@param entry 指向存储读取到的条目信息的缓冲区
@param result 存放下一个目录条目的指针(*result为需要的下一条目信息)
@return 成功返回0,到达目录末尾或发生错误时返回错误码,*result被置为NULL
*/

进入子目录

#include 
int chdir(const char *path);
/**
@brief 将调用进程的当前工作目录更改为path指定的目录
@param path 指向目录名称
@return 成功返回0,失败返回-1,并设置错误码error

错误码error:
EACCES             path的某个组件的搜索权限被拒绝
EFAULT             path指向您的可访问地址空间之外
EIO                出现I/O错误
ELOOP              解析路径时遇到过多符号链接
ENAMETOOLONG     路径太长
ENOENT             目录不存在
ENOMEM             可用的内核内存不足
ENOTDIR         路径的组件不是目录
*/
int fchdir(int fd);
/**
@brief 将调用进程的当前工作目录更改为fd指定的目录
@param fd 指定目录的文件描述符
@return 成功返回指向该目录流下一个目录条目的指针,到达目录末尾或发生错误时返回NULL

错误码error:
EACCES fd上打开的目录的搜索权限被拒绝
EBADF  fd不是有效的文件描述符
*/

关闭目录

#include 
#include 
int closedir(DIR *dirp);
/**
@brief 关闭目录
@param dirp 指向目录流的指针
@return 成功返回0,失败返回-1并设置错误码error
*/

删除文件/目录

#include 
int remove(const char *pathname);
/**
@brief 删除文件或目录。    如果删除的名称是指向文件的最后一个链接,并且没有任何进程打开该文件,则会删除该文件,并使其使用的空间可供重复使用。
如果该名称是指向文件的最后一个链接,但有进程仍打开该文件,则该文件将一直存在,直到引用该文件的最后文件描述符关闭为止。
如果名称引用了符号链接,则会删除该链接。如果名称引用了套接字、FIFO或设备,则该名称将被删除,但打开对象的进程可以继续使用它。
@param pathname 文件或目录的名称
@return 成功返回0,失败返回-1并设置错误码error
*/

目录指针操作

#include 
#include 
void rewinddir(DIR *dirp);
/**
@brief 将目录流dirp的位置重置为目录的开头
@param dirp 指向目录流的指针
*/

#include 
int scandir(const char *dirp, struct dirent ***namelist,
    int (*filter)(const struct dirent *),
    int (*compar)(const struct dirent **, const struct dirent **));
/**
@brief 扫描目录dirp,在每个目录条目上调用filter()。filter()返回非零的条目存储在通过malloc()分配的字符串中,使用带有比较函数compar()的qsort()进行排序,并收集在通过malloc()指定的数组namelist中。如果filter为NULL,则会选择所有条目。
@param dirp 指向目录流的指针
@param namelist 指向存储名称列表的指针
@param filter 筛选条件
@param compar 排序规则
@return 成功返回所选目录项的数量,失败返回-1
*/
int alphasort(const void *a, const void *b);
/**
@brief 可以用作比较函数compar(),使用strcoll()对目录条目(a->d_name, b->d_name)进行排序
@param a 指向struct dirent的指针
@param b 指向struct dirent的指针
*/
int versionsort(const void *s, const void *b);
/**
@brief 可以用作比较函数compar(),使用strverscmp()对目录条目((*a)->d_name, (*b)->d_name)进行排序
@param s 指向struct dirent的指针
@param b 指向struct dirent的指针
@param sb返回正数
*/

#include 
void seekdir(DIR *dirp, long offset);
/**
@brief 设置目录流中的位置,下一次readdir()调用将从该位置开始
@param dirp 指向目录流的指针
@param offset 相对目录流起始位置的偏移量,一般为telldir()的返回值
*/

#include 
long telldir(DIR *dirp);
/**
@brief 返回与目录流dirp相关联的当前位置
@param dirp 指向目录流的指针
@return 成功返回目录流中的当前位置(offset),失败返回-1并设置error
*/

例程

#define _SVID_SOURCE
/* print files in current directory in reverse order */
#include 
int main(void)
{
   struct dirent **namelist;
   int n;

   n = scandir(".", &namelist, 0, alphasort);
   if (n < 0)
   {
       perror("scandir");
   }
   else 
   {
       while (n--) 
       {
           printf("%s\n", namelist[n]->d_name);
           free(namelist[n]);
       }
       free(namelist);
   }
   return 0;
}

获取文件/目录信息

#include 
#include 
#include 
struct stat  
{   
    dev_t       st_dev;     /* ID of device containing file - 文件所在设备的ID*/  
    ino_t       st_ino;     /* inode number - 节点号*/    
    mode_t      st_mode;    /* protection - 保护模式?*/    
    nlink_t     st_nlink;   /* number of hard links - 链向此文件的连接数(硬连接)*/    
    uid_t       st_uid;     /* user ID of owner - 所有者的用户ID*/    
    gid_t       st_gid;     /* group ID of owner - 所有者的组ID*/    
    dev_t       st_rdev;    /* device ID (if special file) - 设备号,针对设备文件*/    
    off_t       st_size;    /* total size, in bytes - 文件大小,字节为单位*/    
    blksize_t   st_blksize; /* blocksize for filesystem I/O - 系统块的大小*/    
    blkcnt_t    st_blocks;  /* number of blocks allocated - 文件所占块数*/    
    time_t      st_atime;   /* time of last access - 最后访问时间*/    
    time_t      st_mtime;   /* time of last modification -最近修改时间*/    
    time_t      st_ctime;   /* time of last status change - 上次状态更改的时间*/    
};
int stat(const char *path, struct stat *buf);
/**
@brief 获取path指向的文件信息,并存储到buf中
@param path 指定的文件名称
@param buf 存储文件信息的缓冲区
@return 成功返回0,失败返回-1并设置error
*/
int lstat(const char *path, struct stat *buf);
/**
@brief 获取path指向的文件信息,并存储到buf中,lstat()与stat()相同,只是如果路径是符号链接,则链接本身是stat,而不是它所引用的文件。
@param path 指定的文件名称
@param buf 存储文件信息的缓冲区
@return 成功返回0,失败返回-1并设置error
*/
int fstat(int fd, struct stat *buf);
/**
@brief 获取fd指向的文件信息,并存储到buf中,fstat()与stat()相同,不同之处在于要统计的文件是由文件描述符fd指定的。
@param fd 指定文件的文件描述符 
@param buf 存储文件信息的缓冲区
@return 成功返回0,失败返回-1并设置error
*/

S_ISREG(m)  is it a regular file?
S_ISDIR(m)  directory?
S_ISCHR(m)  character device?
S_ISBLK(m)  block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)

S_IFMT     0170000   bit mask for the file type bit fields
S_IFSOCK   0140000   socket
S_IFLNK    0120000   symbolic link
S_IFREG    0100000   regular file
S_IFBLK    0060000   block device
S_IFDIR    0040000   directory
S_IFCHR    0020000   character device
S_IFIFO    0010000   FIFO
S_ISUID    0004000   set UID bit
S_ISGID    0002000   set-group-ID bit (see below)
S_ISVTX    0001000   sticky bit (see below)
S_IRWXU    00700     mask for file owner permissions
S_IRUSR    00400     owner has read permission
S_IWUSR    00200     owner has write permission
S_IXUSR    00100     owner has execute permission
S_IRWXG    00070     mask for group permissions
S_IRGRP    00040     group has read permission
S_IWGRP    00020     group has write permission
S_IXGRP    00010     group has execute permission
S_IRWXO    00007     mask for permissions for others (not in group)
S_IROTH    00004     others have read permission
S_IWOTH    00002     others have write permission
S_IXOTH    00001     others have execute permission

例程

#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv[])
{
   struct stat sb;

   if (argc != 2) 
   {
       fprintf(stderr, "Usage: %s \n", argv[0]);
       exit(EXIT_FAILURE);
   }

   if (stat(argv[1], &sb) == -1) 
   {
       perror("stat");
       exit(EXIT_SUCCESS);
   }

   printf("File type:                ");

   switch (sb.st_mode & S_IFMT) 
   {
   case S_IFBLK:  printf("block device\n");            break;
   case S_IFCHR:  printf("character device\n");        break;
   case S_IFDIR:  printf("directory\n");               break;
   case S_IFIFO:  printf("FIFO/pipe\n");               break;
   case S_IFLNK:  printf("symlink\n");                 break;
   case S_IFREG:  printf("regular file\n");            break;
   case S_IFSOCK: printf("socket\n");                  break;
   default:       printf("unknown?\n");                break;
   }

   printf("I-node number:            %ld\n", (long) sb.st_ino);

   printf("Mode:                     %lo (octal)\n",
           (unsigned long) sb.st_mode);

   printf("Link count:               %ld\n", (long) sb.st_nlink);
   printf("Ownership:                UID=%ld   GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

   printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
   printf("File size:                %lld bytes\n",
           (long long) sb.st_size);
   printf("Blocks allocated:         %lld\n",
           (long long) sb.st_blocks);

   printf("Last status change:       %s", ctime(&sb.st_ctime));
   printf("Last file access:         %s", ctime(&sb.st_atime));
   printf("Last file modification:   %s", ctime(&sb.st_mtime));

   exit(EXIT_SUCCESS);
}

读取链接文件

#include 
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
/**
@brief 获取path指向的链接信息,并存储到buf中,buf的大小为bufsize
@param path 指定链接的名称 
@param buf 存储文件信息的缓冲区
@param bufsiz 缓冲区buf的大小,内容过长时将被截断,并不会向buf中写入结束符
@return 成功返回缓冲区buf中的字节数,失败返回-1并设置error
*/

目录操作例程

/**
 * 遍历指定目录及其子目录,后期有时间补充目录/文件的详细信息打印及筛选
 */
#include 
#include 
#include 
#include 
#include 

void listDir(const char *path);

int main(void)
{
    char firstDir[] = "/home/user/test";
    listDir(firstDir);
    
    return 0;
}

void listDir(const char *path)
{
    DIR *pd;
    struct dirent *pdt;
    struct stat sinfo;
    char sName[512];
    
    pd = opendir(path);
    if (!pd) return;
    
    while (pdt=readdir(pd))
    {
        // 跳过"."和".."目录
        if (!strcmp(pdt->d_name, ".") || !strcmp(pdt->d_name, ".."))
            continue;
        
        memset(sName, 0, sizeof(sName));
        sprintf(sName, "%s/%s", path, pdt->d_name);
        
        if (stat(sName, &sinfo) != 0) // 获取信息失败
        {
            printf("failed to get stat, name: %s\n", pdt->d_name);
            continue;
        }
        
        if (S_ISDIR(sinfo.st_mode))
        {
            printf("%s is child dirent\n", pdt->d_name);
            listDir(sName);
        }
        else
        {
            printf("%s is file\n", pdt->d_name);
            
            if (S_ISLNK(sinfo.st_mode))
                printf("%s is S_IFLNK\n", pdt->d_name);
        }
    }
    
    closedir(pd);
}

声明:时间有限,目前仅将相关库函数记录下来,后期慢慢完善用法及例程,感兴趣的小伙伴可以先关注,有更新就会提醒哦~

你可能感兴趣的:(Linux_C语言,linux,c语言,运维,开发语言)