【Linux系统编程】03:文件夹操作

news2024/9/22 4:20:17

文件夹操作


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

NAME
       readdir - read a directory

SYNOPSIS
       #include <dirent.h>

       struct dirent *readdir(DIR *dirp);

DESCRIPTION
       The  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 directory
       stream 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 supported
                                              by 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_reclen
              This is the size (in bytes) of the returned record.  This may not match the size of the structure definition shown
              above; 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 VALUE
       On 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

NAME
       stat, fstat, lstat, fstatat - get file status

SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <unistd.h>

       int stat(const char *pathname, struct stat *statbuf);
       int fstat(int fd, struct stat *statbuf);
       int lstat(const char *pathname, struct stat *statbuf);

       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <sys/stat.h>

       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 >= 200112L

       fstatat():
           Since glibc 2.10:
               _POSIX_C_SOURCE >= 200809L
           Before glibc 2.10:
               _ATFILE_SOURCE

DESCRIPTION
       These  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 structure
       All 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 nanosecond
                  precision 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_mode
              This field contains the file type and mode.  See inode(7) for further information.

       st_nlink
              This 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_rdev
              This field describes the device that this file (inode) represents.

       st_size
              This 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_blksize
              This field gives the "preferred" block size for efficient filesystem I/O.

       st_blocks
              This 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_atime
              This is the file's last access timestamp.

       st_mtime
              This is the file's last modification timestamp.

       st_ctime
              This is the file's last status change timestamp.

       For further information on the above fields, see inode(7).

RETURN VALUE
       On 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)获取statbuff
		if (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);//uid
		printf(" %-8s", ggg_group->gr_name);//gid

		printf(" %-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)获取statbuff
		char 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);//uid
		printf(" %-8s", ggg_group->gr_name);//gid

		printf(" %-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.获取文件夹信息statbuff
	int 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);//uid
	printf(" %-8s", ggg_group->gr_name);//gid

	printf(" %-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.获取文件夹信息statbuff
	if ((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);//uid
	printf(" %-10s", ggg_group->gr_name);//gid

	double 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 5

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 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.获取文件夹信息statbuff
	if ((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);//uid
	printf(" %-10s", ggg_group->gr_name);//gid

	double 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

NAME
       lseek - reposition read/write file offset

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       off_t lseek(int fd, off_t offset, int whence);

DESCRIPTION
       lseek() 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_SET
              The file offset is set to offset bytes.

       SEEK_CUR
              The file offset is set to its current location plus offset bytes.

       SEEK_END
              The 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 holes
       Since version 3.1, Linux supports the following additional values for whence:

       SEEK_DATA
              Adjust 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_HOLE
              Adjust 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 
       		<unistd.h>.

       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 VALUE
       Upon  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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/401307.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SPSS】交叉设计方差分析和协方差分析详细操作教程(附案例实战)

🤵‍♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 目录 方差分析概述 交叉设计方差分析

hibernate学习(三)

session&#xff1a;类似connection对象是连接对象 一、session&#xff1a; 二、session中的API 三、get和load的区别 四、修改方法&#xff1a; void update&#xff08;object obj&#xff09; 五、删除方法&#xff1a; void delete&#xff08;object obj&#xff0…

案例14-代码结构逻辑混乱,页面设计不美观

目录 目录 一&#xff1a;背景介绍 二&#xff1a;思路&方案 三&#xff1a;过程 问题1&#xff1a;代码可读性差&#xff0c;代码结构混乱 问题2&#xff1a; 代码逻辑混乱&#xff0c;缺乏封装的意识 问题3&#xff1a;美观问题&#xff1a;问题和图标没有对应上 四…

最短路专题——Dijkstra、Floyd、Bellman-Ford、SPFA

目录前言一、全源最短路1.1 Floyd二、单源最短路2.1 Dijkstra2.1.1 堆优化版的Dijkstra2.2 Bellman-Ford2.2.1 队列优化版的Bellman-Ford&#xff1a;SPFA前言 BFS是一种朴素的最短路算法&#xff0c;它可以找到无权图或边权都相同的图的最短路&#xff0c;但是对于边权不完全…

AbstractQueuedSynchronizer从入门到踹门

概念设计初衷&#xff1a;该类利用 状态队列 实现了一个同步器&#xff0c;更多的是提供一些模板方法&#xff08;子类必须重写&#xff0c;不然会抛错&#xff09;。 设计功能&#xff1a;独占、共享模式两个核心&#xff0c;state、Queue2.1 statesetState、compareAndSetSta…

LayerNormalization

目录 1.BN的问题 1.1 BN与batch size 1.2 BN与RNN 2.LN详解 2.1 MLP中的LN 2.2 RNN中的LN 2.3 LN与ICS和损失平面平滑 BN不适用于RNN等动态网络和batchsize较小的时候效果不好。LayerNormalization的提出有效的解决BN的这两个问题。LN和BN不同点是归一化的维度是互相垂直…

SQL总结-排名的使用

##一、通过排名或者范围条件连表筛选特殊行 第一行最后一行区间&#xff08;第一行到第二行或者连续区间&#xff09;找中位数通过排名进行分组或者连续区间 ######1.使用条件筛选连表找区间 Employee 表保存了一年内的薪水信息。 请你编写 SQL 语句&#xff0c;来查询每个…

基于ChatRWKV智能问答和内容创作

ChatRWKV是对标ChatGPT的开源项目,希望做大规模语言模型的Stable Diffusion,测试很一段时间确实很像ChatGPT,从使用方法和内容结果上都很相似,但是还有一些差异。 文章目录 准备工作环境配置创建虚拟环境激活虚拟环境pip安装匹配版本ChatRWKV 使用模型替换常用参数设置使用…

手机磁吸背夹散热器制冷快速方案

手机散热器是什么&#xff1f;手机散热器分为几种类型&#xff1f;手机散热的方式都有哪些&#xff1f; 因为经常玩游戏&#xff0c;手机发热得厉害&#xff0c;都可以煎鸡蛋了&#xff0c;心想着要买个东西给手机散散热&#xff0c;没想到还真的有手机散热器。 不知道手机散…

mysql锁分类大全

前言 为什么会出现锁 MySQL中的锁是为了保证并发操作的正确性和一致性而存在的。 当多个用户同时对同一份数据进行操作时&#xff0c;如果不加控制地进行读写操作&#xff0c;就可能导致数据不一致的问题。例如&#xff0c;当多个用户同时对同一行数据进行写操作时&#xff…

uniapp使用webview嵌入vue页面及通信

最近刚做的一个需求&#xff0c;web端&#xff08;Vue&#xff09;使用了FormMaking库&#xff0c;FormMaking是一个拖拉拽的动态设计表单、快速开发的一个东西&#xff0c;拖拽完之后最终可以导出一个很长的json&#xff0c;然后通过json再进行回显&#xff0c;快速开发&#…

【Spring Boot】Spring Boot经典面试题分享

文章目录1. SpringBoot 简介2. SpringBoot 的优缺点3. SpringBoot 固定版本4. SpringBoot 的使用方式5. SpringBoot 自动配置原理6. PropertySource7. ImportResource8. springboot 的 profile 加载9. SpringBoot 激活指定 profile 的几种方式10. SpringBoot 项目内部配置文件加…

项目中用到的责任链模式

目录 1.什么是责任链&#xff1f;它的原理是什么&#xff1f; 2.应用场景 ​3.项目中的应用 传送门&#xff1a;策略模式&#xff0c;工作中你用上了吗&#xff1f; 1.什么是责任链&#xff1f;它的原理是什么&#xff1f; 将请求的发送和接收解耦&#xff0c;让多个接收对象…

NetApp AFF A900:针对任务关键型应用程序的解决方案

NetApp AFF A900&#xff1a;适用于数据中心的解决方案 AFF A 系列中的 AFF A900 高端 NVMe 闪存存储功能强大、安全可靠、具有故障恢复能力&#xff0c;提供您为任务关键型企业级应用程序提供动力并保持数据始终可用且安全所需的一切。 AFF A900&#xff1a;针对任务关键型应…

关于BLE的一些知识总结

数据包长度对于BLE4.0/4.1来说&#xff0c;一个数据包的有效载荷最大为20字节对于BLE4.2以上&#xff0c;数据包的有效载荷扩大为251字节传输速率在不考虑跳频间隔的情况下&#xff0c;最大传输速率为&#xff1a;1&#xff09;BLE4.0/4.1的理论吞吐率为39kb/s&#xff1b;2&am…

523-(ZCU102E的pin兼容替代卡) 基于 XCZU15EG的双 FMC通用信号处理板

&#xff08;ZCU102E的pin兼容替代卡&#xff09; 基于 XCZU15EG的双 FMC通用信号处理板 一、板卡概述 本板卡基于Xilinx Zynq Ultrascale MPSOC系列SOC XCZU15EG-FFVB1156架构&#xff0c;PS端搭载一组64-bit DDR4&#xff0c;容量32Gb&#xff0c;最高可稳定运行在240…

solidworks调用toolbox出现未配置怎么办

问题背景 本人最近在跟随B站恶补solidworks&#xff0c;学习链接如下 https://www.bilibili.com/video/BV1iw411Z7HZ/?spm_id_from333.337.search-card.all.click 但是在学习的过程中遇到了这样的问题 智能点现在配置&#xff0c;正常的应该是这样的 扒拉了网上所有的解决办…

04从零开始学Java之可能是最详细的Java环境配置教程

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者前言在上一篇文章中&#xff0c;壹哥给大家重点讲解了Java实现跨平台的原理&#xff0c;不知道你现在有没有弄清楚呢&#xff1f;如…

window vscode编辑appsmith源码

前言 本来最开始用的idea打开wsl中的appsmith&#xff0c;卡得一批。最后没办法&#xff0c;用自己的电脑装成ubuntu server&#xff0c;然后vscode的远程开发对appsmith源码进行编辑。如果自己电脑内存16个G或者更大可能打开wsl中的估计会还好&#xff0c;我公司电脑只有8g所…

Virtualbox Vagrant 迁移与恢复

前 言 window10电脑重新安装C盘。重装前正常使用的VirtualBox虚拟机&#xff0c;启动失败&#xff0c;先是启动报各种找不到{uuid.vmdk}文件的错误&#xff0c;使用原来的虚拟机配置文件虽然能正常启动&#xff0c;但是关闭虚拟机后&#xff0c;xxx.vbox配置文件的快照顺序又被…