当前位置:网站首页>The C programming language (version 2) notes / 8 UNIX system interfaces / 8.6 instances (directory list)
The C programming language (version 2) notes / 8 UNIX system interfaces / 8.6 instances (directory list)
2022-06-12 16:28:00 【M rookie M】
8.6 example ( Directory listing )
We often need to perform another operation on the file system , To get information about the file , Instead of reading the contents of the file
The directory listing program is an example of this , such as UNIX command ls, It prints the file name in a directory and some other optional information , Such as file length 、 Access rights, etc
MS-DOS In the operating system dir The command has a similar function
because UNIX A directory in is a file , therefore ,ls Just read this file to get all the file names
however , If you need to get other information about the file , Such as length, etc , You need to use system calls
In some other systems , Even getting the file name requires a system call , For example, in MS-DOS This is the case in the system
Whether or not the implementation is related to the specific system , We need to provide a system independent access to file information
The following procedure will be adopted fsize Make that clear fsize Procedure is ls A special form of command , It prints the length of all files specified in the command line parameter table
If one of the files is a directory , be fsize The program will recursively call itself... To this directory
If there are no arguments on the command line , be fsize The program handles the current directory
Let's first review UNIX The structure of the file system
stay UNIX In the system , A directory is a file , This file contains a list of file names and information indicating the location of these files
“ Location ” Is a table that points to other tables ( namely inode surface ) The index of
Of documents inode It is the place where all the file information except the file name is stored
Catalog items (directory entry) Usually contains only two entries : File name and inode Number
In different versions of the system , The format of the directory is different from the exact content
therefore , In order to isolate the non portable parts , We divided the task into two parts
The outer layer defines a called Dirent The structure and 3 A function opendir、readdir and closedir
They provide system independent pairs of names and... In directory entries inode Numbered access
We will use this interface to write fsize Program , And then explain how to communicate with Version 7 and System V UNIX These functions are implemented on systems with the same directory structure
Other situations are reserved for practice
structure Dirent contain inode Number and file name
The maximum length of a file name is determined by NAME_MAX Set up ,NAME_MAX The value of is determined by the system opendir Return a point called DIR Pointer to the structure of , The structure and structure FILE similar , It will be readdir and closedir Use
All this information is stored in the header file dirent.h in
#define NAME_MAX 14 /* longest filename component; */
/* system-dependent */
typedef struct {
/* portable directory entry */
long ino; /* inode number */
char name[NAME_MAX+1]; /* name + '\0' terminator */
} Dirent;
typedef struct {
/* minimal DIR: no buffering, etc. */
int fd; /* file descriptor for the directory */
Dirent d; /* the directory entry */
} DIR;
DIR *opendir(char *dirname);
Dirent *readdir(DIR *dfd);
void closedir(DIR *dfd);
system call stat Take the file name as the parameter , Return the file's inode All information in , If something goes wrong , Then return to -1:
char *name;
struct stat stbuf;
int stat(char *, struct stat *);
stat(name, &stbuf);
It names the file name Of the file inode Information filling structure stbuf in
describe stat Structure definition of return value , The header file is included in <sys/stat.h> in
A typical form of this structure is shown below :
struct stat /* inode information returned by stat */
{
dev_t st_dev; /* device of inode */
ino_t st_ino; /* inode number */
short st_mode; /* mode bits */
short st_nlink; /* number of links to file */
short st_uid; /* owners user id */
short st_gid; /* owners group id */
dev_t st_rdev; /* for special files */
off_t st_size; /* file size in characters */
time_t st_atime; /* time last accessed */
time_t st_mtime; /* time last modified */
time_t st_ctime; /* time originally created */
};
dev_t and ino_t And so on <sys/types.h> In the definition of , This file must be included in the program
st_mode Item contains a series of flags that describe the file , The signs are in <sys/stat.h> In the definition of
We only need to deal with the relevant parts of the file type :
#define S_IFMT 0160000 /* type of file: */
#define S_IFDIR 0040000 /* directory */
#define S_IFCHR 0020000 /* character special */
#define S_IFBLK 0060000 /* block special */
#define S_IFREG 0010000 /* regular */
/* ... */
Let's start writing the program fsize
If by stat The pattern obtained by calling indicates that a file is not a directory , It is easy to get the length of the file , And output directly
however , If the file is a directory , The files in the directory must be processed one by one
Because this directory may contain subdirectories , So the process is recursive
The main program main Handling command line arguments , And pass each parameter to the function fsize
#include <stdio.h>
#include <string.h>
#include "syscalls.h"
#include <fcntl.h> /* flags for read and write */
#include <sys/types.h> /* typedefs */
#include <sys/stat.h> /* structure returned by stat */
#include "dirent.h"
void fsize(char *)
/* print file name */
main(int argc, char **argv)
{
if (argc == 1) /* default: current directory */
fsize(".");
else
while (--argc > 0)
fsize(*++argv);
return 0;
}
function fsize Print the length of the file
however , If this file is a directory , be fsize First call dirwalk Function handles all the files it contains
Notice how to use the file <sys/stat.h> Flag name in S_IFMT and S_IFDIR To determine whether the file is a directory
Brackets are required , because & Operator takes precedence over == Operator precedence
int stat(char *, struct stat *);
void dirwalk(char *, void (*fcn)(char *));
/* fsize: print the name of file "name" */
void fsize(char *name)
{
struct stat stbuf;
if (stat(name, &stbuf) == -1) {
fprintf(stderr, "fsize: can't access %s\n", name);
return;
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
dirwalk(name, fsize);
printf("%8ld %s\n", stbuf.st_size, name);
}
function dirwalk Is a general-purpose function , It calls the function... For each file in the directory fcn once
It first opens the directory , Loop through each of these files , And call this function for each file , Then close the directory and return to
because fsize The function calls... For each directory dirwalk function , So these two functions are called recursively to each other
#define MAX_PATH 1024
/* dirwalk: apply fcn to all files in dir */
void dirwalk(char *dir, void (*fcn)(char *))
{
char name[MAX_PATH];
Dirent *dp;
DIR *dfd;
if ((dfd = opendir(dir)) == NULL) {
fprintf(stderr, "dirwalk: can't open %s\n", dir);
return;
}
while ((dp = readdir(dfd)) != NULL) {
if (strcmp(dp->name, ".") == 0 || strcmp(dp->name, ".."))
continue; /* skip self and parent */
if (strlen(dir)+strlen(dp->name)+2 > sizeof(name))
fprintf(stderr, "dirwalk: name %s %s too long\n", dir, dp->name);
else {
sprintf(name, "%s/%s", dir, dp->name);
(*fcn)(name);
}
}
closedir(dfd);
}
Every time you call readdir Will return a pointer , It points to the information of the next file
If there are no pending files in the directory , This function will return NULL
Each directory contains itself . And parent directory .. Project , They must be skipped during processing , Otherwise it will lead to an infinite loop
Up to now , The code is independent of the format of the directory
The next step is to provide a on a specific system opendir、readdir and closedir The simplest version of
The following functions apply to Version 7 and System V UNIX System , They use header files <sys/dir.h> Directory information in :
#ifndef DIRSIZ
#define DIRSIZ 14
#endif
struct direct {
/* directory entry */
ino_t d_ino; /* inode number */
char d_name[DIRSIZ]; /* long name does not have '\0' */
};
Some versions of the system support longer file names and more complex directory structures
type ino_t It's using typedef The type of definition , It is used to describe inode Index of tables
In the system we usually use , This type is unsigned short, But this information should not be used in the program
Because this type may be different in different systems , So use typedef The definition is better
be-all “ System ” Type can be found in file <sys/types.h> Find
opendir Function first opens the directory , Verify that this file is a directory ( Call system call fstat, It is associated with stat similar , But it takes the file descriptor as a parameter )
Then assign a directory structure , And save the information :
int fstat(int fd, struct stat *);
/* opendir: open a directory for readdir calls */
DIR *opendir(char *dirname)
{
int fd;
struct stat stbuf;
DIR *dp;
if ((fd = open(dirname, O_RDONLY, 0)) == -1
|| fstat(fd, &stbuf) == -1
|| (stbuf.st_mode & S_IFMT) != S_IFDIR
|| (dp = (DIR *) malloc(sizeof(DIR))) == NULL)
return NULL;
dp->fd = fd;
return dp;
}
closedir Function to close a catalog file and free memory space :
/* closedir: close directory opened by opendir */
void closedir(DIR *dp)
{
if (dp) {
close(dp->fd);
free(dp);
}
}
Last , function readdir Use read The system call reads each directory entry
If a directory location is not currently in use ( Because a file was deleted ), Then it's inode The number is 0, And skip the position
otherwise , take inode Number and directory name are placed in one static In the structure of type , And return a pointer to this structure to the user
Every time you call readdir Function will overwrite the information obtained from the previous call
#include <sys/dir.h> /* local directory structure */
/* readdir: read directory entries in sequence */
Dirent *readdir(DIR *dp)
{
struct direct dirbuf; /* local directory structure */
static Dirent d; /* return: portable structure */
while (read(dp->fd, (char *) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)) {
if (dirbuf.d_ino == 0) /* slot not in use */
continue;
d.ino = dirbuf.d_ino;
strncpy(d.name, dirbuf.d_name, DIRSIZ);
d.name[DIRSIZ] = '\0'; /* ensure termination */
return &d;
}
return NULL;
}
Even though fsize The program is very special , But it does illustrate some important ideas
First , Many programs are not “ System program ”, They only use information maintained by the operating system
For such a program , The important thing is , The representation of information only appears in the standard header file , The program that uses them only needs to include these header files in the file , There is no need to include the corresponding declaration
secondly , It is possible to create a system independent interface for system related objects
Functions in the standard library are a good example
边栏推荐
- 面试:hashCode()和equals()
- Super detailed dry goods! Docker+pxc+haproxy build a MySQL Cluster with high availability and strong consistency
- <山东大学项目实训>渲染引擎系统(五)
- [research] reading English papers -- the welfare of researchers in English poor
- 《安富莱嵌入式周报》第268期:2022.05.30--2022.06.05
- Global and Chinese markets for air sampling calibration pumps 2022-2028: Research Report on technology, participants, trends, market size and share
- Acwing 797 differential
- 深入理解 Go Modules 的 go.mod 与 go.sum
- acwing 800. 数组元素的目标和
- 数据库的三大范式
猜你喜欢
随机推荐
acwing 高精度乘法
std::set compare
批量--03---CmdUtil
Object.keys遍历一个对象
QCustomplot笔记(一)之QCustomplot添加数据以及曲线
The C Programming Language(第 2 版) 笔记 / 8 UNIX 系统接口 / 8.7 实例(存储分配程序)
Batch --03---cmdutil
Servlet API
Interview: difference between '= =' and equals()
Collect | 22 short videos to learn Adobe Illustrator paper graphic editing and typesetting
MongoDB系列之SQL和NoSQL的区别
acwing 801. Number of 1 in binary (bit operation)
acwing 801. 二进制中1的个数(位运算)
<山东大学项目实训>渲染引擎系统(六)
HEMA is the best representative of future retail
acwing795 前缀和(一维)
深入理解 Go Modules 的 go.mod 与 go.sum
PostgreSQL source code (53) plpgsql syntax parsing key processes and function analysis
Global and Chinese market of vascular prostheses 2022-2028: Research Report on technology, participants, trends, market size and share
acwing 803. Interval merging








