【Linux系统编程】03:文件夹操作
创始人
2024-05-31 23:53:06
0

文件夹操作


OVERVIEW

  • 文件夹操作
      • 一、文件夹操作
        • 1.修改目录chdir
        • 2.打开目录opendir
        • 3.关闭目录closedir
        • 4.读取目录readdir
        • 5.文件信息获取stat
      • 二、案例使用
        • 1.ls实现
        • 2.stat文件信息获取
        • 3.ls -la主要实现
        • 4.ls -la重点修改
        • 5.ls -la文件字典序
        • 6.ls -la文件颜色显示
      • 三、补充操作
        • 1.文件定位lseek
        • 2.文件控制fcntl

一、文件夹操作

1.修改目录chdir

image-20230210140414788

2.打开目录opendir

image-20230210144113236

3.关闭目录closedir

image-20230210144431966

4.读取目录readdir

NAMEreaddir - read a directorySYNOPSIS#include struct dirent *readdir(DIR *dirp);DESCRIPTIONThe  readdir()  function  returns  a  pointer  to a dirent structure representing the next directory entry in the directory stream pointed to by dirp.  It returns NULL on reaching the end of the directorystream or if an error occurred.In the glibc implementation, the dirent structure is defined as follows:struct dirent {ino_t          d_ino;       /* Inode number */off_t          d_off;       /* Not an offset; see below */unsigned short d_reclen;    /* Length of this record */unsigned char  d_type;      /* Type of file; not supportedby all filesystem types */char           d_name[256]; /* Null-terminated filename */};The only fields in the dirent structure that are mandated by POSIX.1 are d_name and d_ino.  The other fields are unstandardized, and not present on all systems; see NOTES below for some further details.The fields of the dirent structure are as follows:d_ino  This is the inode number of the file.d_off  The value returned in d_off is the same as would be returned by calling telldir(3) at the current position in the directory stream.  Be aware that despite its type and name, the d_off field is sel‐dom any kind of directory offset on modern filesystems.  Applications should treat this field as an opaque value, making no assumptions about its contents; see also telldir(3).d_reclenThis is the size (in bytes) of the returned record.  This may not match the size of the structure definition shownabove; see NOTES.d_type This field contains a value indicating the file type, making it possible to avoid the expense of calling lstat(2) if further actions depend on the type of the file.When  a suitable feature test macro is defined (_DEFAULT_SOURCE on glibc versions since 2.19, or _BSD_SOURCE on glibc versions 2.19 and earlier), glibc defines the following macro constants for the value returned in d_type:DT_BLK      This is a block device.DT_CHR      This is a character device.DT_DIR      This is a directory.DT_FIFO     This is a named pipe (FIFO).DT_LNK      This is a symbolic link.DT_REG      This is a regular file.DT_SOCK     This is a UNIX domain socket.DT_UNKNOWN  The file type could not be determined.Currently, only some filesystems (among them: Btrfs, ext2, ext3, and ext4) have full support for returning the                   file type in d_type.  All applications must properly handle a return of DT_UNKNOWN.d_name This field contains the null terminated filename.  See NOTES.The data returned by readdir() may be overwritten by subsequent calls to readdir() for the same directory stream.RETURN VALUEOn success, readdir() returns a pointer to a dirent structure.  (This structure may be statically allocated; do not attempt to free(3) it.)If the end of the directory stream is reached, NULL is returned and errno is not changed.  If an error occurs, NULL is returned and errno is set appropriately.  To distinguish end of stream  and  from  an error, set errno to zero before calling readdir() and then check the value of errno if NULL is returned.

image-20230210144522891

5.文件信息获取stat

NAMEstat, fstat, lstat, fstatat - get file statusSYNOPSIS#include #include #include int stat(const char *pathname, struct stat *statbuf);int fstat(int fd, struct stat *statbuf);int lstat(const char *pathname, struct stat *statbuf);#include            /* Definition of AT_* constants */#include int fstatat(int dirfd, const char *pathname, struct stat *statbuf,int flags);Feature Test Macro Requirements for glibc (see feature_test_macros(7)):lstat():/* glibc 2.19 and earlier */ _BSD_SOURCE|| /* Since glibc 2.20 */ _DEFAULT_SOURCE|| _XOPEN_SOURCE >= 500|| /* Since glibc 2.10: */ _POSIX_C_SOURCE >= 200112Lfstatat():Since glibc 2.10:_POSIX_C_SOURCE >= 200809LBefore glibc 2.10:_ATFILE_SOURCEDESCRIPTIONThese  functions  return  information about a file, in the buffer pointed to by statbuf.  No permissions are required on the file itself, but—in the case of stat(), fstatat(), and lstat()—execute (search) permission is required on all of the directories in pathname that lead to the file.stat() and fstatat() retrieve information about the file pointed to by pathname; the differences for fstatat() are described below.lstat() is identical to stat(), except that if pathname is a symbolic link, then it returns information about the link itself, not the file that it refers to.fstat() is identical to stat(), except that the file about which information is to be retrieved is specified by the file descriptor fd.The stat structureAll of these system calls return a stat structure, which contains the following fields:struct stat {dev_t     st_dev;         /* ID of device containing file */ino_t     st_ino;         /* Inode number */mode_t    st_mode;        /* File type and mode */nlink_t   st_nlink;       /* Number of hard links */uid_t     st_uid;         /* User ID of owner */gid_t     st_gid;         /* Group ID of owner */dev_t     st_rdev;        /* Device ID (if special file) */off_t     st_size;        /* Total size, in bytes */blksize_t st_blksize;     /* Block size for filesystem I/O */blkcnt_t  st_blocks;      /* Number of 512B blocks allocated *//* Since Linux 2.6, the kernel supports nanosecondprecision for the following timestamp fields.For the details before Linux 2.6, see NOTES. */struct timespec st_atim;  /* Time of last access */struct timespec st_mtim;  /* Time of last modification */struct timespec st_ctim;  /* Time of last status change */#define st_atime st_atim.tv_sec      /* Backward compatibility */#define st_mtime st_mtim.tv_sec#define st_ctime st_ctim.tv_sec};Note: the order of fields in the stat structure varies somewhat across architectures.  In addition, the definition above does not show the padding bytes that may be present between some fields on  various architectures.  Consult the glibc and kernel source code if you need to know the details.Note:  for performance and simplicity reasons, different fields in the stat structure may contain state information from different moments during the execution of the system call.  For example, if st_mode or st_uid is changed by another process by calling chmod(2) or chown(2), stat() might return the old st_mode together with the new st_uid, or the old st_uid together with the new st_mode.The fields in the stat structure are as follows:st_dev This field describes the device on which this file resides.  (The major(3) and minor(3) macros may be useful to decompose the device ID in this field.)st_ino This field contains the file's inode number.st_modeThis field contains the file type and mode.  See inode(7) for further information.st_nlinkThis field contains the number of hard links to the file.st_uid This field contains the user ID of the owner of the file.st_gid This field contains the ID of the group owner of the file.st_rdevThis field describes the device that this file (inode) represents.st_sizeThis field gives the size of the file (if it is a regular file or a symbolic link) in bytes.  The size of a symbolic link is the length of the pathname it contains, without a terminating null byte.st_blksizeThis field gives the "preferred" block size for efficient filesystem I/O.st_blocksThis field indicates the number of blocks allocated to the file, in 512-byte units.  (This may be smaller than st_size/512 when the file has holes.)st_atimeThis is the file's last access timestamp.st_mtimeThis is the file's last modification timestamp.st_ctimeThis is the file's last status change timestamp.For further information on the above fields, see inode(7).RETURN VALUEOn success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

二、案例使用

1.ls实现

#include "head.h"int main(int argc, char *argv[]) {char dir_name[256] = {0};DIR *dir = NULL;if (argc == 1) {strcpy(dir_name, ".");//只有命令没有参数 则使用缺省值参数} else {strcpy(dir_name, argv[1]);}//判定文件夹是否打开成功if ((dir = opendir(dir_name)) == NULL) {perror("opendir");exit(1);}//文件夹读取while (1) {struct dirent *dir_file;if ((dir_file = readdir(dir)) == NULL) break;printf("%s  ", dir_file->d_name);//打印文件的名字}printf("\n");closedir(dir);return 0;
}

image-20230210151315309

2.stat文件信息获取

#include "head.h"int main(int argc, char *argv[]) {char dir_name[50] = {0};//文件名字if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);	}int stat_num;//返回值情况struct stat statbuff;//statbuff结构体if ((stat_num = stat(dir_name, &statbuff)) == -1) {perror("stat");exit(1);}printf("%ld %s", statbuff.st_ino, dir_name);printf("\n");return 0;
}

image-20230210183738875

#include "head.h"int main(int argc, char *argv[]) {char dir_name[256] = {0};DIR *dir = NULL;if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);}if ((dir = opendir(dir_name)) == NULL) {perror("opendir");exit(1);}//文件夹信息读取while (1) {struct stat statbuff;struct dirent *dir_file;if ((dir_file = readdir(dir)) == NULL) break;stat(dir_file->d_name, &statbuff);char type;mode_t val = statbuff.st_mode;switch (val & S_IFMT) {case S_IFLNK: type = 'l'; break;case S_IFIFO: type = 'p'; break;case S_IFREG: type = '-'; break;case S_IFDIR : type = 'd'; break;default: break;}printf("%ld  %c  %s\n", statbuff.st_ino, type, dir_file->d_name);}printf("\n");closedir(dir);return 0;
}

image-20230210190204893

3.ls -la主要实现

#include "head.h"int main(int argc, char *argv[]) {char dir_name[256] = {0};DIR *dir = NULL;//1.打开文件夹if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);}if ((dir = opendir(dir_name)) == NULL) {perror("opendir");exit(1);}//2.文件夹信息读取while (1) {int stat_num;struct stat statbuff;struct dirent *dir_file = NULL;if ((dir_file = readdir(dir)) == NULL) break;//循环遍历文件夹//(1)获取statbuffif (stat_num = lstat(dir_file->d_name, &statbuff) != 0) {printf("%s\n", dir_file->d_name);perror("stat");exit(1);}//(2)从statbuff中获取各类信息char type;mode_t val = statbuff.st_mode;switch (val & S_IFMT) {case S_IFBLK:  type = 'b'; break;//printf("block device\n");case S_IFCHR:  type = 'c'; break;//printf("character device\n");case S_IFDIR:  type = 'd'; break;//printf("directory\n");case S_IFIFO:  type = 'p'; break;//printf("FIFO/pipe\n");case S_IFLNK:  type = 'l'; break;//printf("symlink\n");case S_IFREG:  type = '-'; break;//printf("regular file\n");case S_IFSOCK: type = 's'; break;//printf("socket\n");default: printf("unknown?\n");break;}struct passwd *gpu_passwd;struct group *ggg_group;gpu_passwd = getpwuid(statbuff.st_uid);//获取用户uid信息ggg_group = getgrgid(statbuff.st_gid);//获取用户gid信息//(3)打印从statbuff中获取的各类信息printf("%ld ", statbuff.st_ino);printf("%c", type);printf("%c", (val & S_IRUSR) ? 'r' : '-');printf("%c", (val & S_IWUSR) ? 'w' : '-');printf("%c", (val & S_IXUSR) ? 'x' : '-');printf("%c", (val & S_IRGRP) ? 'r' : '-');printf("%c", (val & S_IWGRP) ? 'w' : '-');printf("%c", (val & S_IXGRP) ? 'x' : '-');printf("%c", (val & S_IROTH) ? 'r' : '-');printf("%c", (val & S_IWOTH) ? 'w' : '-');printf("%c", (val & S_IXOTH) ? 'x' : '-');printf(" %2ld", statbuff.st_nlink);//链接文件个数printf(" %-8s", gpu_passwd->pw_name);//uidprintf(" %-8s", ggg_group->gr_name);//gidprintf(" %-8ld", statbuff.st_size);//文件大小printf("%.12s ",ctime(&statbuff.st_mtime)+4);//文件修改时间printf(" %s", dir_file->d_name);//文件名printf("\n");}closedir(dir);return 0;
}

image-20230211155224037

报错原因:

  • Linux中的stat函数只能访问用户当前所在的路径下的文件(即pwd命令所提示的目录),该路径下的文件夹无法递归访问。stat函数无法返回文件属性。
  • 只有文件为绝对路径的情况下,才能获取到文件的stat状态
  • 参见文章Linux中的stat函数只能访问当前用户所在目录。

4.ls -la重点修改

#include "head.h"int main(int argc, char *argv[]) {char dir_name[256] = {0};DIR *dir = NULL;//1.打开文件夹if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);while(--argc) printf("%s:\n",*++argv);//打印目标路径}if ((dir = opendir(dir_name)) == NULL) {perror("opendir");exit(1);}//2.文件夹信息读取while (1) {int stat_num;struct stat statbuff;struct dirent *dir_file = NULL;if ((dir_file = readdir(dir)) == NULL) break;//循环遍历文件夹//(1)获取statbuffchar full_path[512];//为解决stat报错问题 改用full_path绝对路径传入stat函数sprintf(full_path, "%s/%s", dir_name, dir_file->d_name);if (stat_num = lstat(full_path, &statbuff) != 0) {perror("stat");exit(1);}//(2)从statbuff中获取各类信息char type;mode_t val = statbuff.st_mode;switch (val & S_IFMT) {case S_IFBLK:  type = 'b'; break;//printf("block device\n");case S_IFCHR:  type = 'c'; break;//printf("character device\n");case S_IFDIR:  type = 'd'; break;//printf("directory\n");case S_IFIFO:  type = 'p'; break;//printf("FIFO/pipe\n");case S_IFLNK:  type = 'l'; break;//printf("symlink\n");case S_IFREG:  type = '-'; break;//printf("regular file\n");case S_IFSOCK: type = 's'; break;//printf("socket\n");default: printf("unknown?\n");break;}struct passwd *gpu_passwd;struct group *ggg_group;gpu_passwd = getpwuid(statbuff.st_uid);//获取用户uid信息ggg_group = getgrgid(statbuff.st_gid);//获取用户gid信息//(3)打印从statbuff中获取的各类信息printf("%ld ", statbuff.st_ino);printf("%c", type);printf("%c", (val & S_IRUSR) ? 'r' : '-');printf("%c", (val & S_IWUSR) ? 'w' : '-');printf("%c", (val & S_IXUSR) ? 'x' : '-');printf("%c", (val & S_IRGRP) ? 'r' : '-');printf("%c", (val & S_IWGRP) ? 'w' : '-');printf("%c", (val & S_IXGRP) ? 'x' : '-');printf("%c", (val & S_IROTH) ? 'r' : '-');printf("%c", (val & S_IWOTH) ? 'w' : '-');printf("%c", (val & S_IXOTH) ? 'x' : '-');printf(" %2ld", statbuff.st_nlink);//链接文件个数printf(" %-8s", gpu_passwd->pw_name);//uidprintf(" %-8s", ggg_group->gr_name);//gidprintf(" %-8ld", statbuff.st_size);//文件大小printf("%.12s ",ctime(&statbuff.st_mtime)+4);//文件修改时间printf(" %s", dir_file->d_name);//文件名printf("\n");}closedir(dir);return 0;
}

image-20230211160715904

//程序重构
#include "head.h"void dols(char*);
void printInfo(char*, struct stat);int main(int argc, char *argv[]) {char dir_name[256] = {0};//文件夹名称if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);while(--argc) printf("%s:\n",*++argv);//打印目标路径}dols(dir_name);return 0;
}void dols(char *dir_name) {DIR *dir = NULL;//1.打开文件夹if ((dir = opendir(dir_name)) == NULL) {perror("opendir");exit(1);}//2.获取文件夹信息statbuffint stat_num;struct stat statbuff;struct dirent *dir_file = NULL;while ((dir_file = readdir(dir)) != NULL) {char full_path[512];sprintf(full_path, "%s/%s", dir_name, dir_file->d_name);if (stat_num = lstat(full_path, &statbuff) != 0) {perror("stat");exit(1);}//3.打印从statbuff中获取的各类信息printInfo(dir_file->d_name, statbuff);}closedir(dir);
}void printInfo(char *fileName, struct stat statbuff) {char type;mode_t val = statbuff.st_mode;switch (val & S_IFMT) {case S_IFBLK:  type = 'b'; break;//printf("block device\n");case S_IFCHR:  type = 'c'; break;//printf("character device\n");case S_IFDIR:  type = 'd'; break;//printf("directory\n");case S_IFIFO:  type = 'p'; break;//printf("FIFO/pipe\n");case S_IFLNK:  type = 'l'; break;//printf("symlink\n");case S_IFREG:  type = '-'; break;//printf("regular file\n");case S_IFSOCK: type = 's'; break;//printf("socket\n");default: printf("unknown?\n");break;}struct passwd *gpu_passwd;struct group *ggg_group;gpu_passwd = getpwuid(statbuff.st_uid);//获取用户uid信息ggg_group = getgrgid(statbuff.st_gid);//获取用户gid信息printf("%ld ", statbuff.st_ino);printf("%c", type);printf("%c", (val & S_IRUSR) ? 'r' : '-');printf("%c", (val & S_IWUSR) ? 'w' : '-');printf("%c", (val & S_IXUSR) ? 'x' : '-');printf("%c", (val & S_IRGRP) ? 'r' : '-');printf("%c", (val & S_IWGRP) ? 'w' : '-');printf("%c", (val & S_IXGRP) ? 'x' : '-');printf("%c", (val & S_IROTH) ? 'r' : '-');printf("%c", (val & S_IWOTH) ? 'w' : '-');printf("%c", (val & S_IXOTH) ? 'x' : '-');printf(" %2ld", statbuff.st_nlink);//链接文件个数printf(" %-8s", gpu_passwd->pw_name);//uidprintf(" %-8s", ggg_group->gr_name);//gidprintf(" %-8ld", statbuff.st_size);//文件大小printf("%.12s ",ctime(&statbuff.st_mtime)+4);//文件修改时间printf(" %s", fileName);//文件名printf("\n");
}

5.ls -la文件字典序

  • 此功能非核心
  • ls -la按照文件名称进行字典序排序。
  • 对文件大小的显示进行修改

思路

  1. 创建一个全局变量的数组filename用于记录所有文件名称,以及全局的计数变量file_cnt
  2. 先将目录中的文件名存入数组中,然后对文件名进行排序,排完序后再根据已排序的文件名来获取stat数据即可
#include "head.h"void dols(char*);
void printInfo(char*, struct stat);char *filenames[4096];//存放数组名的数组
int file_cnt = 0; //目录中文件个数
void errorHandle(char *);
void sort(char** , int , int);
int partition(char** , int , int);
int compare(char* , char*);
void swap(char **, char **);int main(int argc, char *argv[]) {char dir_name[256] = {0};//文件夹名称if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);while(--argc) printf("%s:\n",*++argv);//打印目标路径}dols(dir_name);return 0;
}void dols(char *dir_name) {DIR *dir = NULL;//1.获取文件名称并对文件名排序 存储在filename数组中if ((dir = opendir(dir_name)) == NULL) errorHandle("opendir");struct dirent *dir_file = NULL;while((dir_file = readdir(dir))) filenames[file_cnt++] = dir_file->d_name;//将目录下的文件名全部存入filename中sort(filenames, 0, file_cnt-1);//对文件名进行字典序排序closedir(dir);//2.获取文件夹信息statbuffif ((dir = opendir(dir_name)) == NULL) errorHandle("opendir");int stat_num;struct stat statbuff;for (int i = 0; i < file_cnt; ++i) {char full_path[512];sprintf(full_path, "%s/%s", dir_name, filenames[i]);if (stat_num = lstat(full_path, &statbuff) != 0) errorHandle("stat");//3.打印从statbuff中获取的各类信息printInfo(filenames[i], statbuff);}closedir(dir);
}void printInfo(char *fileName, struct stat statbuff) {char type;mode_t val = statbuff.st_mode;switch (val & S_IFMT) {case S_IFBLK:  type = 'b'; break;//printf("block device\n");case S_IFCHR:  type = 'c'; break;//printf("character device\n");case S_IFDIR:  type = 'd'; break;//printf("directory\n");case S_IFIFO:  type = 'p'; break;//printf("FIFO/pipe\n");case S_IFLNK:  type = 'l'; break;//printf("symlink\n");case S_IFREG:  type = '-'; break;//printf("regular file\n");case S_IFSOCK: type = 's'; break;//printf("socket\n");default: printf("unknown?\n");break;}struct passwd *gpu_passwd;struct group *ggg_group;gpu_passwd = getpwuid(statbuff.st_uid);//获取用户uid信息ggg_group = getgrgid(statbuff.st_gid);//获取用户gid信息printf("%-8ld ", statbuff.st_ino);printf("%c", type);printf("%c", (val & S_IRUSR) ? 'r' : '-');printf("%c", (val & S_IWUSR) ? 'w' : '-');printf("%c", (val & S_IXUSR) ? 'x' : '-');printf("%c", (val & S_IRGRP) ? 'r' : '-');printf("%c", (val & S_IWGRP) ? 'w' : '-');printf("%c", (val & S_IXGRP) ? 'x' : '-');printf("%c", (val & S_IROTH) ? 'r' : '-');printf("%c", (val & S_IWOTH) ? 'w' : '-');printf("%c", (val & S_IXOTH) ? 'x' : '-');printf(" %2ld", statbuff.st_nlink);//链接文件个数printf(" %-10s", gpu_passwd->pw_name);//uidprintf(" %-10s", ggg_group->gr_name);//giddouble size = (double)statbuff.st_size / 1024.00;//文件大小if (size <= 0) {printf("%8ld", statbuff.st_size);} else {printf("%7.1fK", size);}printf("\t%.12s ",ctime(&statbuff.st_mtime)+4);//文件修改时间printf(" %s", fileName);//文件名printf("\n");
}void errorHandle(char *error) {perror(error);exit(1);
}//以下为字典序排序模块
void sort(char** filenames, int start, int end) {if(start < end) {int position = partition(filenames, start, end);sort(filenames, start, position - 1);sort(filenames, position + 1, end);}
}int partition(char** filenames, int start, int end) {if(!filenames) return -1;char* privot = filenames[start];while(start < end) {while(start < end && compare(privot, filenames[end]) < 0) end--;swap(&filenames[start], &filenames[end]);while(start < end && compare(privot, filenames[start]) >= 0) start++;swap(&filenames[start], &filenames[end]);}return start;
}void swap(char **a, char **b) {char *temp;temp = *a;*a = *b;*b = temp;
}int compare(char* s1,char* s2) {if(*s1=='.') s1++;if(*s2=='.') s2++;while(*s1 && *s2 && *s1 == *s2) {s1++; s2++;if(*s1=='.') s1++;if(*s2=='.') s2++;}return *s1 - *s2;
}

image-20230211215658083

6.ls -la文件颜色显示

不同文件显示出来对应的颜色也是不一样的

  • 目录文件是蓝色
  • 可执行文件绿色
  • 普通文件白色
#include "head.h"#define WHITE 0
#define BLUE  1
#define GREEN 2
#define RED   3
#define LBLUE 4
#define YELLOW 5void dols(char*);
void printInfo(char*, struct stat);char *filenames[4096];//存放数组名的数组
int file_cnt = 0; //目录中文件个数
void errorHandle(char *);
void sort(char** , int , int);
int partition(char** , int , int);
int compare(char* , char*);
void swap(char **, char **);int getColor(struct stat );
void printfColor(char*, int);int main(int argc, char *argv[]) {char dir_name[256] = {0};//文件夹名称if (argc == 1) {strcpy(dir_name, ".");} else {strcpy(dir_name, argv[1]);while(--argc) printf("%s:\n",*++argv);//打印目标路径}dols(dir_name);return 0;
}void dols(char *dir_name) {DIR *dir = NULL;//1.获取文件名称并对文件名排序 存储在filename数组中if ((dir = opendir(dir_name)) == NULL) errorHandle("opendir");struct dirent *dir_file = NULL;while((dir_file = readdir(dir))) filenames[file_cnt++] = dir_file->d_name;//将目录下的文件名全部存入filename中sort(filenames, 0, file_cnt-1);//对文件名进行字典序排序closedir(dir);//2.获取文件夹信息statbuffif ((dir = opendir(dir_name)) == NULL) errorHandle("opendir");int stat_num;struct stat statbuff;for (int i = 0; i < file_cnt; ++i) {char full_path[512];sprintf(full_path, "%s/%s", dir_name, filenames[i]);if (stat_num = lstat(full_path, &statbuff) != 0) errorHandle("stat");//3.打印从statbuff中获取的各类信息printInfo(filenames[i], statbuff);}closedir(dir);
}void printInfo(char *filename, struct stat statbuff) {char type;mode_t val = statbuff.st_mode;switch (val & S_IFMT) {case S_IFBLK:  type = 'b'; break;//printf("block device\n");case S_IFCHR:  type = 'c'; break;//printf("character device\n");case S_IFDIR:  type = 'd'; break;//printf("directory\n");case S_IFIFO:  type = 'p'; break;//printf("FIFO/pipe\n");case S_IFLNK:  type = 'l'; break;//printf("symlink\n");case S_IFREG:  type = '-'; break;//printf("regular file\n");case S_IFSOCK: type = 's'; break;//printf("socket\n");default: printf("unknown?\n");break;}struct passwd *gpu_passwd;struct group *ggg_group;gpu_passwd = getpwuid(statbuff.st_uid);//获取用户uid信息ggg_group = getgrgid(statbuff.st_gid);//获取用户gid信息printf("%-8ld ", statbuff.st_ino);printf("%c", type);printf("%c", (val & S_IRUSR) ? 'r' : '-');printf("%c", (val & S_IWUSR) ? 'w' : '-');printf("%c", (val & S_IXUSR) ? 'x' : '-');printf("%c", (val & S_IRGRP) ? 'r' : '-');printf("%c", (val & S_IWGRP) ? 'w' : '-');printf("%c", (val & S_IXGRP) ? 'x' : '-');printf("%c", (val & S_IROTH) ? 'r' : '-');printf("%c", (val & S_IWOTH) ? 'w' : '-');printf("%c", (val & S_IXOTH) ? 'x' : '-');printf(" %2ld", statbuff.st_nlink);//链接文件个数printf(" %-10s", gpu_passwd->pw_name);//uidprintf(" %-10s", ggg_group->gr_name);//giddouble size = (double)statbuff.st_size / 1024.00;//文件大小if (size < 1) {printf("%8ld", statbuff.st_size);} else {printf("%7.1fK", size);}printf("\t%.12s ",ctime(&statbuff.st_mtime)+4);//文件修改时间int color = getColor(statbuff);//打印文件名printfColor(filename, color);printf("\n");
}void errorHandle(char *error) {perror(error);exit(1);
}//以下为字典序排序模块
void sort(char** filenames, int start, int end) {if(start < end) {int position = partition(filenames, start, end);sort(filenames, start, position - 1);sort(filenames, position + 1, end);}
}int partition(char** filenames, int start, int end) {if(!filenames) return -1;char* privot = filenames[start];while(start < end) {while(start < end && compare(privot, filenames[end]) < 0) end--;swap(&filenames[start], &filenames[end]);while(start < end && compare(privot, filenames[start]) >= 0) start++;swap(&filenames[start], &filenames[end]);}return start;
}void swap(char **a, char **b) {char *temp;temp = *a;*a = *b;*b = temp;
}int compare(char* s1,char* s2) {if(*s1=='.') s1++;if(*s2=='.') s2++;while(*s1 && *s2 && *s1 == *s2) {s1++; s2++;if(*s1=='.') s1++;if(*s2=='.') s2++;}return *s1 - *s2;
}//以下文文件颜色显示模块
int getColor(struct stat buff) {//对不同的文件类型给不同的颜色int color = 0;if(S_ISLNK(buff.st_mode)) color = LBLUE;else if(S_ISDIR(buff.st_mode)) color = BLUE;else if(S_ISCHR(buff.st_mode) ||S_ISBLK(buff.st_mode)) color = YELLOW;else if(buff.st_mode & S_IXUSR) color = GREEN;return color;
}void printfColor(char *name,int color) {//打印有颜色的文件名if(color == GREEN) printf("\033[1m\033[32m%-22s\033[0m",name);else if(color == BLUE) printf("\033[1m\033[34m%-22s\033[0m",name);else if(color == WHITE) printf("%-22s",name);else if(color == LBLUE) printf("\033[1m\033[36m%-22s\033[0m",name);else if(color == YELLOW) printf("\033[1m\033[33m%-22s\033[0m",name);
}

image-20230211221225962

  • https://developer.aliyun.com/article/899337

  • https://developer.aliyun.com/article/899338

三、补充操作

1.文件定位lseek

每个打开的文件都会记录当前的读写位置,

  • 打开文件时读写位置为0表示文件的开头,通常读写多少字节,文件位置就会向后移动多少字节。
  • 以O_APPEND方式打开文件,每次写操作都会在文件末尾追加数据,读写位置移动到新的文件的末尾。

image-20230213105508076

NAMElseek - reposition read/write file offsetSYNOPSIS#include #include off_t lseek(int fd, off_t offset, int whence);DESCRIPTIONlseek() repositions the file offset of the open file description associated with the file descriptor fd to the argument offset according to the directive whence as follows:SEEK_SETThe file offset is set to offset bytes.SEEK_CURThe file offset is set to its current location plus offset bytes.SEEK_ENDThe file offset is set to the size of the file plus offset bytes.lseek()  allows  the  file  offset to be set beyond the end of the file (but this does not change the size of the file).  			If data is later written at this point, subsequent reads of the data in the gap (a "hole") return null bytes ('\0') until data is actually written into the gap.Seeking file data and holesSince version 3.1, Linux supports the following additional values for whence:SEEK_DATAAdjust the file offset to the next location in the file greater than or equal to offset containing data.  If offset points to data, then the file offset is set to offset.SEEK_HOLEAdjust the file offset to the next hole in the file greater than or equal to offset.  If offset points into the middle of a hole, then the file offset is set to offset.  If there is  no  hole  past offset, then the file offset is adjusted to the end of the file (i.e., there is an implicit hole at the end of any file).In both of the above cases, lseek() fails if offset points past the end of the file.These  operations  allow  applications  to  map  holes in a sparsely allocated file.  This can be useful for applications such as file backup tools, which can save space when creating backups and preserve holes, if they have a mechanism for discovering holes.For the purposes of these operations, a hole is a sequence of zeros that (normally) has not been allocated in the underlying file storage.  However, a filesystem is not obliged to report holes, so these operations are not a guaranteed mechanism for mapping the storage space actually allocated to a file.  (Furthermore, sequence of zeros that actually has been written to the underlying storage may not be reported as a hole.)  In the simplest implementation, a filesystem can support the operations by making SEEK_HOLE always return the offset of the end of the file, and making SEEK_DATA always return offset (i.e., even if the location referred to by offset is a hole, it can be considered to consist of data that is a sequence of zeros).The _GNU_SOURCE feature test macro must be defined in order to obtain the definitions of SEEK_DATA and SEEK_HOLE from .The SEEK_HOLE and SEEK_DATA operations are supported for the following filesystems:*  Btrfs (since Linux 3.1)*  OCFS (since Linux 3.2)*  XFS (since Linux 3.5)*  ext4 (since Linux 3.8)*  tmpfs(5) (since Linux 3.8)*  NFS (since Linux 3.18)*  FUSE (since Linux 4.5)RETURN VALUEUpon  successful completion, lseek() returns the resulting offset location as measured in bytes from the beginning of the file.  On error, the value (off_t) -1 is returned and errno is set to indicate the error.
//通过lseek文件定位 确定文件大小
#include"head.h"int main(int argc, char* argv[]) {//1.打开一个文件 以只读的方式 并判定是否打开成功int fd;if ((fd = open(argv[1], O_RDONLY)) < 0) {perror("open");exit(1);}//2.读入1个字符 并进行打印操作printf("position %ld\n", lseek(fd, 0, SEEK_CUR));char c;read(fd, &c, 1);write(STDOUT_FILENO, &c, 1);//3.通过lseek确定当前指针在文件中的位置printf("\nposition %ld\n", lseek(fd, 0, SEEK_CUR));//4.通过lseek移动文件位置printf("\nposition %ld\n", lseek(fd, 3, SEEK_CUR));read(fd, &c, 1);write(STDOUT_FILENO, &c, 1);//5.通过lseek确定文件的大小printf("\nposition %ld\n", lseek(fd, 0, SEEK_END));//文件读取的位置直接移动到文件末尾(测量文件大小/字节)return 0;
}

image-20230214094834934

2.文件控制fcntl

fcntl函数用来改变已打开文件的属性,而不必重新open文件,可以重新设置读、写、追加、非阻塞等标志。

image-20230214095513125

#include"head.h"int main(int argc, char* argv[]) {//1.打开一个文件 以只读的方式 并判定是否打开成功int fd;if ((fd = open(argv[1], O_RDONLY)) < 0) {perror("open");exit(1);}//2.fcntl设置文件属性int flag;flag |= O_NONBLOCK;//利用或等于操作 为文件设置非阻塞属性fcntl(fd, F_SETFL, flag);//3.fcntl获取文件属性if ((flag = fcntl(fd, F_GETFL)) < 0) {perror("fcntl");exit(1);}switch (flag & O_ACCMODE) {case O_RDONLY:printf("rdonly\n");break;case O_WRONLY:printf("wronly\n");break;case O_RDWR:printf("rdwr\n");break;default:printf("no\n");break;}if ((flag & O_NONBLOCK) == O_NONBLOCK) printf("O_NONBLOCK\n");//printf("O_NONBLOCK = %d = %o\n", flag & O_NONBLOCK, flag & O_NONBLOCK);//4.fcntl取消文件权限flag &= ~O_NONBLOCK;fcntl(fd, F_SETFL, flag);if ((flag & O_NONBLOCK) != O_NONBLOCK) printf("O_BLOCK\n");return 0;
}

image-20230215131146148

相关内容

热门资讯

申请函格式 申请函格式范文(精选8篇)  在市场经济发展迅速的今天,申请书使用的次数愈发增长,申请书是我们提出请...
培训申请书 培训申请书范文(通用13篇)  在眼下市场经济活跃的社会,我们每个人都可能要用到申请书,我们在写申请...
优秀学生干部的申请书 优秀学生干部的申请书范文(精选6篇)  在现在的社会生活中申请书与我们的关系越来越密切,在写作上,申...
养老保险申请书 养老保险申请书范文  在如今这个年代,申请书与我们不再陌生,写申请书的时候要注意内容的完整。那么写申...
市场招待费申请范文7篇 市场招待费申请范文 第一篇人事处:本人系商学院经济学系教师,报名参加由教育部高等教育司重点支持(项目...
励志奖学金的申请书范文 励志奖学金的申请书范文  一、奖学金申请书的含义  奖学金申请书指的是被学校认定的经济困难学生、优秀...
大学生贫困申请书模板800字 大学生贫困申请书模板800字  写申请书的注意事项  (1)申请的事项要写清楚、具体,涉及的数据要准...
商标注册申请书 商标注册申请书范文商标注册申请书怎么写呢?以下是小编为大家搜集提供到的有关商标注册申请书范文,欢迎阅...
事业单位调动工作申请书范文 为你推荐事业单位上的调动工作的申请书,小编为你推荐。范文1:公司人力资源部:您好!我叫……,感谢您百...
申请劳动仲裁需要什么材料   申请劳动仲裁需要的三类材料,具体哪些材料?下面就跟小编来了解一下!  申请劳动仲裁需要的材料,可...
社工师加薪申请书 加薪申请书范文(一)尊敬的:您好!我自年月份有幸进入公司以来,近年了,期间始终抱着“是我家,繁荣靠大...
少年先锋队入队申请书 少年先锋队入队申请书  敬爱的少先队:  我自愿加入中国少年先锋队,这是我的梦想,也是我的目标。  ...
单位岗位补助申请范文简短通用... 单位岗位补助申请范文简短 第一篇尊敬各位领导:我是联运公司994车队职工XX,86年部队转业安置到公...
特色产业补贴申请范文推荐46... 特色产业补贴申请范文 第一篇尊敬的公司领导:因酒店客房前期开荒,需要加大安全管理力度和物资搬运。现本...
试用员工转正申请表怎么写 试用员工转正申请表怎么写  转正申请书人力资源部:  我叫XX,是本公司XX部员工,自XX年X月X日...
学校申请打井报告范文优选16... 学校申请打井报告范文 第一篇今年,我县遭受特大旱灾,我处四个农业村1085亩水稻,有95%以上因缺水...
课题申请书 课题申请书模板10篇  在当今不断发展的世界,申请书在现实生活中使用广泛,写申请书的时候要注意内容的...
优秀班集体的申请书 优秀班集体的申请书范文(精选8篇)  现今社会公众的追求意识不断提升,申请书在生活中的使用越来越广泛...
减租申请书 减租申请书范文(精选6篇)  随着时代在进步,用到申请书的地方很多,我们在写申请书的时候要注意态度要...
教师人事调动申请书 尊敬的领导:您们好!我们夫妻(刘军、贾容)同为合江教育事业战线上的人民教师;现将我们的工作及生活情况...