Unix/Linux编程实践读书笔记

Unix/Linux编程实践教程

作者: Bruce Molay
原作名: Understanding UNIX/LINUX Programming
译者: 杨宗源 / 黄海涛 

第1章  Unix系统编程概述  

  通过三个方法理解学习系统编程

  • 分析程序
  • 学习系统调用
  • 编程实现

对应三个问题

  what does it do->how does it work->let's write our own version

more 的实现

  more的实现版本1 

 1 /**
 2  * read and print 24 lines then pause for a few special commands
 3  */
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 
 9 #define PAGELEN 24
10 #define LINELEN 512
11 void do_more(FILE*);
12 int see_more();
13 
14 int main(int ac, char *av[]) {
15   FILE* fp;
16   if (ac == 1) {
17     do_more(stdin);
18   } else {
19     while (--ac) {
20       if ((fp = fopen(*++av, "r")) != NULL) {
21         do_more(fp);
22         fclose(fp);
23       } else {
24         exit(1);
25       }
26     }
27   }
28   return 0;
29 }
30 
31 /**
32  * read PAGELEN lines, then call see_more() for further instructions
33  */
34 void do_more(FILE* fp) {
35   char line[LINELEN];
36   int num_of_lines = 0;
37   int see_more(), reply;
38   while (fgets(line, LINELEN, fp)) {
39     if (num_of_lines == PAGELEN) {
40       reply = see_more();
41       if (reply == 0)
42         break;
43       num_of_lines -= reply;
44     }
45     if (fputs(line, stdout) == EOF)
46       exit(1);
47     num_of_lines++;
48   }
49 }
50 
51 /**
52  * print message, wait for response, return # of lines to advance
53  * q means no, space means yes, CR means one line
54  */
55 int see_more() {
56   int c;
57   printf("\033[7m more? \033[m");
58   while ((c = getchar()) != EOF) {
59     if (c == 'q')
60       return 0;
61     if (c == ' ')
62       return PAGELEN;
63     if (c == '\n')
64       return 1;
65   }
66   return 0;
67 }
more01

  上述版本存在许多问题,比如输入q和空格后,需要按回车,而且输入是有回显的。

输入重定向问题

cat more01.c  | more

cat more01.c  | ./more01

  more01的标准输入重定向到了cat命令的标准输出,而程序中使用getchar(),从标准输入读取数据,此时就会出现问题。

解决办法是,从标准输入中读入分页数据,改为从键盘读用户输入。

  more的实现版本2 

 1 /**
 2  * read and print 24 lines then pause for a few special commands
 3  * feature of version 0.2: reads from /dev/tty for commands
 4  */
 5 
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <string.h>
 9 
10 #define PAGELEN 24
11 #define LINELEN 512
12 void do_more(FILE*);
13 int see_more(FILE*);
14 
15 int main(int ac, char *av[]) {
16   FILE* fp;
17   if (ac == 1) {
18     do_more(stdin);
19   } else {
20     while (--ac) {
21       if ((fp = fopen(*++av, "r")) != NULL) {
22         do_more(fp);
23         fclose(fp);
24       } else {
25         exit(1);
26       }
27     }
28   }
29   return 0;
30 }
31 
32 /**
33  * read PAGELEN lines, then call see_more() for further instructions
34  */
35 void do_more(FILE* fp) {
36   char line[LINELEN];
37   int num_of_lines = 0;
38   int reply;
39 
40   FILE* fp_tty = fopen("/dev/tty", "r");
41   if (fp_tty == NULL)
42     exit(1);
43 
44   while (fgets(line, LINELEN, fp)) {
45     if (num_of_lines == PAGELEN) {
46       reply = see_more(fp_tty);
47       if (reply == 0)
48         break;
49       num_of_lines -= reply;
50     }
51     if (fputs(line, stdout) == EOF)
52       exit(1);
53     num_of_lines++;
54   }
55 }
56 
57 /**
58  * print message, wait for response, return # of lines to advance
59  * q means no, space means yes, CR means one line
60  */
61 int see_more(FILE* cmd) {
62   int c;
63   printf("\033[7m more? \033[m");
64   while ((c = getc(cmd)) != EOF) {
65     if (c == 'q')
66       return 0;
67     if (c == ' ')
68       return PAGELEN;
69     if (c == '\n')
70       return 1;
71   }
72   return 0;
73 }
more02

  文件/dev/tty,是键盘和显示器的设备描述文件,向这个文件写相当于显示在用户的屏幕上,读相当于从键盘获取用户的输入。即使程序的输入/输出被重定向,程序仍可通过这个文件同终端交换数据。

第2章  用户、文件操作与联机帮助:编写who命令 

概念

  • 联机帮助作用与使用方法;
  • 文件操作、建立读写;
  • 缓冲:用户级缓冲与内核级缓冲;
  • 内核模式、用户模式和系统调用的代价;

命令who

who命令能做些什么?

  执行who命令,查看手册帮助man who,

localhost ~]$ man who
WHO(1) User Commands WHO(1)

NAME
who - show who is logged on

SYNOPSIS
who [OPTION]... [ FILE | ARG1 ARG2 ]

DESCRIPTION
Print information about users who are currently logged in.

-a, --all
same as -b -d --login -p -r -t -T -u

who命令是如何工作的?

从unix中学习unix

  • 阅读联机帮助
  • 搜索联机帮助
  • 阅读.h文件
  • 从参阅部分得到启示

阅读联机帮助

localhost ~]$ man who

...

DESCRIPTION

...

If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common. If ARG1
ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.

...

  从描述中可以看到通常使用文件 /var/run/utmp. /var/log/wtmp 

搜索联机帮助

localhost ~]$ man -k utmp
dump-utmp (8) - print an utmp file in human-readable format.
getutmp (3) - copy utmp structure to utmpx, and vice versa
getutmpx (3) - copy utmp structure to utmpx, and vice versa
utmp (5) - login records
endutent (3) - access utmp file entries

  或可直接使用man utmp

从搜索的联机帮助中看到 utmp (5) - login records,查找该帮助

localhost ~]$ man 5 utmp
UTMP(5) Linux Programmer's Manual UTMP(5)

NAME
utmp, wtmp - login records

SYNOPSIS
#include <utmp.h>

DESCRIPTION
The utmp file allows one to discover information about who is currently using the system.
There may be more users currently using the system, because not all programs use utmp log‐ging.

阅读.h文件

  上述帮助 man 5 utmp,给出了结构体 utmp 的描述

The file is a sequence of utmp structures, declared as follows in <utmp.h> (note that this
is only one of several definitions around; details depend on the version of libc):

当然也可查找阅读.h源文件

localhost ~]$ sudo find / -name "utmp.h"
find: ‘/run/user/1000/gvfs’: Permission denied
/usr/lib/x86_64-redhat-linux6E/include/bits/utmp.h
/usr/lib/x86_64-redhat-linux6E/include/utmp.h
/usr/include/bits/utmp.h
/usr/include/utmp.h

who的工作原理

  who 通过读文件获取需要的信息,每个登录的用户信息都记录在文件中。文件中的结构存放用户登录信息,读取信息并显示出来实现who操作。

如何编写who

  • 从文件中读取数据结构
  • 将结构中的信息以适当的方式显示出来

查找联机帮助获取文件读写方法:man -k file | grep read

...
pwrite64 (2) - read from or write to a file descriptor at a given offset
read (2) - read from a file descriptor
read (3p) - read from a file
readahead (2) - perform file readahead into page cache
...

man 2 read

得到函数原型  ssize_t read(int fd, void *buf, size_t count);

SEE ALSO
close(2), fcntl(2), ioctl(2), lseek(2), open(2), pread(2), readdir(2), readlink(2),
readv(2), select(2), write(2), fread(3)

通过open 获取文件描述符。

通过open帮助,找到对close的引用。

因此整个过程使用open,read,close系统调用。

who1版本

 1 /**
 2  * open, read UTMP file, and show
 3  */
 4 
 5 #include <stdio.h>
 6 #include <utmp.h>
 7 #include <fcntl.h>
 8 #include <unistd.h>
 9 #include <stdlib.h>
10 
11 #define SHOWHOST
12 
13 void show_info(struct utmp*);
14 
15 int main() {
16   struct utmp current_record;
17   int utmpfd;
18   int reclen = sizeof(current_record);
19 
20   printf("Utmp_file = %s\n\n",UTMP_FILE);
21   if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1) {
22     perror(UTMP_FILE);
23     exit(1);
24   }
25 
26   while (read(utmpfd, &current_record, reclen) == reclen)
27     show_info(&current_record);
28   close(utmpfd);
29   return 0;
30 }
31 
32 /**
33  * display cotents of the utmp struct in human readable form
34  * *note* these sizes should not be hardwired
35  */
36 void show_info(struct utmp* utbufp) {
37   printf("%-8.8s", utbufp->ut_user);
38   printf(" ");
39   printf("%-8.8s", utbufp->ut_line);
40   printf(" ");
41   printf("%10d", utbufp->ut_time);
42   printf(" ");
43   #ifdef SHOWHOST
44   printf("(%s)", utbufp->ut_host);
45   #endif
46   printf("\n");
47 }
who1

其中宏UTMP_FILE  为 /var/run/utmp

grep "UTMP_FILE" /usr/include/utmp.h
#define UTMP_FILE _PATH_UTMP
#define UTMP_FILENAME _PATH_UTMP

grep "_PATH_UTMP" /usr/include/*.h
/usr/include/paths.h:#define _PATH_UTMP "/var/run/utmp"
/usr/include/utmp.h:#define UTMP_FILE _PATH_UTMP
/usr/include/utmp.h:#define UTMP_FILENAME _PATH_UTMP
/usr/include/utmpx.h:# define UTMPX_FILE _PATH_UTMPX
/usr/include/utmpx.h:# define UTMPX_FILENAME _PATH_UTMPX

改进地方:正确显示登录时间,去除空白记录。

去除空白记录

utmp结构体中成员 ut_type 值为7的时候,表示这是一个已经登录的用户,据此修改程序消除空白行。

以可读方式显示登录时间

 man -k time | grep transform

 man -k time | grep convert

 man ctime

 编写cp(读和写) 

  • 问题1:cp命令能做些什么 
  • 问题2:cp命令是如何创建/重写文件的 
  • 问题3:如何编写cp 

代码

 1 /**
 2  * uses read and write with tunable buffer size
 3  */
 4 #include <stdio.h>
 5 #include <unistd.h>
 6 #include <fcntl.h>
 7 #include <stdlib.h>
 8 
 9 #define BUFFERSIZE 4096
10 #define COPYMODE 0644
11 
12 void oops(char *, char *);
13 
14 int main(int argc, char *argv[]) {
15   int in_fd, out_fd, n_chars;
16   char buf[BUFFERSIZE];
17 
18   if (argc != 3) {
19     fprintf(stderr, "usage: %s source destination\n", *argv);
20     exit(1);
21   }
22 
23   if ((in_fd = open(argv[1], O_RDONLY)) == -1)
24     oops("Cannot open ", argv[1]);
25 
26   if ((out_fd = creat(argv[2], COPYMODE)) == -1)
27     oops("Cannot create ", argv[2]);
28 
29   // copy files
30   while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0) {
31     if (write(out_fd, buf, n_chars) != n_chars)
32       oops("Write error to ", argv[2]);
33   }
34 
35   if (n_chars == -1)
36     oops("Read error from ", argv[1]);
37 
38   if (close(in_fd) == -1 || close(out_fd) == -1)
39     oops("Error closing files", "");
40 
41   return 0;
42 }
43 
44 void oops(char *s1, char *s2) {
45   fprintf(stderr, "Error: %s ", s1);
46   perror(s2);
47   exit(1);
48 }
cp1

提高文件I/O效率的方法:使用缓冲 

缓冲区的大小对性能的影响 

为什么系统调用需要很多时间 

在who2中添加缓冲区,每次读取多个结构体数据,减少系统调用次数。

 1 /**
 2  * utmplib.h - function to buffer read from utmp file
 3  * functions are
 4  *   utmp_open(filename) - open file
 5  *     return -1 on error
 6  *   utmp_next()         - return pointer to next struct
 7  *     return NULL on eof
 8  *   ump_close()         - close file
 9  *
10  * read NRECS per read and then doles them out from the buffer
11  */
12 
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <utmp.h>
17 
18 #define NRECS 16
19 #define NULLUT ((struct utmp *)NULL)
20 #define UTSIZE (sizeof(struct utmp))
21 
22 static char utmpbuf[NRECS * UTSIZE];  // storage
23 static int  num_recs;                 // num stored
24 static int  cur_rec;                  // next to go
25 static int  fd_utmp = -1;             // read from
26 
27 int utmp_open(char *filename) {
28   fd_utmp = open(filename, O_RDONLY);
29   cur_rec = num_recs = 0;
30   return fd_utmp;
31 }
32 
33 int utmp_reload() {
34   int amt_read;
35   amt_read = read(fd_utmp, utmpbuf, NRECS * UTSIZE);
36   num_recs = amt_read / UTSIZE;
37   cur_rec = 0;
38   return num_recs;
39 }
40 
41 struct utmp * utmp_next() {
42   struct utmp *recp;
43   if (fd_utmp == -1)
44     return NULLUT;
45   if (cur_rec == num_recs && utmp_reload() == 0)
46     return NULLUT;
47 
48   recp = (struct utmp *)&utmpbuf[cur_rec * UTSIZE];
49   cur_rec++;
50   return recp;
51 }
52 
53 void utmp_close() {
54   if (fd_utmp != -1)
55     close(fd_utmp);
56 }
utmplib.c

主函数

 1 /**
 2  * command 'who' with buffered reads
 3  * - open, read UTMP file, and show
 4  * - suppresses empty records
 5  * - formats time nicely
 6  * - buffers input (using utmplib)
 7  */
 8 
 9 #include <stdio.h>
10 #include <utmp.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <time.h>
15 #include "utmplib.c"
16 
17 #define SHOWHOST
18 void show_time(long);
19 void show_info(struct utmp*);
20 
21 int main() {
22   struct utmp * utbufp;
23 
24   if (utmp_open(UTMP_FILE) == -1) {
25     perror(UTMP_FILE);
26     exit(1);
27   }
28 
29   while ((utbufp = utmp_next()) != ((struct utmp *)NULL))
30     show_info(utbufp);
31   utmp_close();
32   return 0;
33 }
34 
35 /**
36  * display cotents of the utmp struct in human readable form
37  * *note* these sizes should not be hardwired
38  */
39 void show_info(struct utmp* utbufp) {
40   if (utbufp->ut_type != USER_PROCESS) // user only
41     return;
42 
43   printf("%-8.8s", utbufp->ut_name);
44   printf(" ");
45   printf("%-8.8s", utbufp->ut_line);
46   printf(" ");
47   show_time(utbufp->ut_time);
48   #ifdef SHOWHOST
49   if (utbufp->ut_host[0] != '\0')
50     printf("(%s)", utbufp->ut_host);
51   #endif
52   printf("\n");
53 }
54 
55 /**
56  * display time in a format fit for human consumption
57  * use ctime to build a string then picks pars out of it
58  * Node: %12.12s prints a string 12 chars wide and LIMITS
59  * it to 12 chars
60  */
61 void show_time(long timeval) {
62   char *cp;
63   cp = ctime(&timeval); // looks like: Mon Feb 4 00:46:40 EST 1991
64   printf("%12.12s", cp + 4);
65 }
who3

内核缓冲技术 

  应用缓冲技术对提高系统效率是明显的,主要思想是一次读入大量的数据存入缓冲区,需要的时候然后从缓冲区读取数据。

  内核模式和用户模式之间的切换需要时间,相比之下,磁盘的I/O操作消耗更多时间,效率更低,因此也需要缓冲技术。

  内核将磁盘上的数据块复制到内核缓冲区,当一个用户空间中的进程需要从磁盘上读数据时,内核一般不直接读磁盘,而是将内核缓冲区的数据复制到进程缓冲区。

  从理论上讲,内核可以在任何时候写磁盘,但不是任意一次write操作都会导致内核的写动作,内核会把要写的数据缓存在内核缓冲区,积累到一定数量后,再一次性写入磁盘。

  应用内核缓冲技术结果:

  • 提高磁盘I/O效率,
  • 优化磁盘写操作,
  • 需及时的将缓存数据写入磁盘。

 第3章  目录与文件属性:编写Is 

问题1:ls命令能做什么 

问题2:ls是如何工作的 

man -k direct | grep read

readdir (3) - read a directory
readdir_r (3) - read a directory
seekdir (3) - set the position of the next readdir() call in the directory stream.
readdir (2) - read directory entry
readdir (3p) - read a directory
readdir_r (3p) - read a directory
readlinkat (2) - read value of a symbolic link relative to a directory file descriptor

问题3:如何编写ls 

ls算法如下

main

  opendir

  while(readdir)

    print dname

  closedir

实现代码ls1

 1 /**
 2  * purpose list contents of directory or directories
 3  * action if no args, user . else list files args
 4  */
 5 
 6 #include <stdio.h>
 7 #include <unistd.h>
 8 #include <dirent.h>
 9 
10 void do_ls(char[]);
11 
12 int main(int argc, char *argv[]) {
13   if (argc == 1) {
14     do_ls(".");
15   } else {
16     while (--argc) {
17       printf("%s:\n", *++argv);
18       do_ls(*argv);
19     }
20   }
21 }
22 
23 /**
24  * list files in directory called dirname
25  */
26 void do_ls(char dirname[]) {
27   DIR *dir_ptr;
28   struct dirent *direntp;
29 
30   if ((dir_ptr = opendir(dirname)) == NULL) {
31     fprintf(stderr, "ls1: cannot open %s \n", dirname);
32   } else {
33     while ((direntp = readdir(dir_ptr)) != NULL) {
34       printf("%s\n", direntp->d_name);
35     }
36     closedir(dir_ptr);
37   }
38 }
ls1

  上述版本还能做什么

  排序,分栏,隐藏. ..目录,选项 -l等

编写ls -l

  问题1:ls-l能做些什么

  问题2:ls-l是如何工作的 

 man -k file | grep -i information

 man -k file | grep status

 实现ls -l

  显示文件状态信息代码:显示模式,链接数,文件所有者,组,大小,最后修改时间,文件名

 1 /**
 2  * - use stat() to obtain and print file properties
 3  * - some members are just numbers
 4  */
 5 #include <stdio.h>
 6 #include <unistd.h>
 7 #include <sys/stat.h>
 8 
 9 void show_stat_info(char *fname, struct stat *buf);
10 
11 int main(int argc, char *argv[]) {
12   struct stat info;
13 
14   if (argc > 1) {
15     if (stat(argv[1], &info) != -1) {
16       show_stat_info(argv[1], &info);
17       return 0;
18     }
19   } else {
20     perror(argv[1]);
21   }
22   return 1;
23 }
24 
25 /**
26  * display some info from stat in a name = value format
27  */
28 void show_stat_info(char *fname, struct stat *buf) {
29   printf("    mode: %o\n", buf->st_mode);
30   printf("   links: %lu\n", buf->st_nlink);
31   printf("    user: %d\n", buf->st_uid);
32   printf("   group: %d\n", buf->st_gid);
33   printf("    size: %ld\n", buf->st_size);
34   printf(" modtime: %ld\n", buf->st_mtime);
35   printf("    name: %s\n", fname);
36 }
fileinfo.c

编译运行结果如下

cc -o fileinfo fileinfo.c
@localhost]$ ./fileinfo fileinfo.c
mode: 100644
links: 1
user: 1000
group: 1000
size: 1152
modtime: 1029894340

将模式字段转化成字符,将用户/组ID转换为字符串

  1 /**
  2  * purpose list contents of directory or directories
  3  * action if no args, user . else list files args
  4  * note: users stat and pwd.h and grp.h
  5  * BUG: try ls2 /tmp
  6  */
  7 
  8 #include <stdio.h>
  9 #include <unistd.h>
 10 #include <dirent.h>
 11 #include <sys/stat.h>
 12 #include <string.h>
 13 #include <time.h>
 14 
 15 void do_ls(char[]);
 16 void do_stat(char *);
 17 void show_file_info(char *, struct stat *);
 18 void mode_to_letters(int, char []);
 19 char * uid_to_name(uid_t);
 20 char * gid_to_name(gid_t);
 21 
 22 int main(int argc, char *argv[]) {
 23   if (argc == 1) {
 24     do_ls(".");
 25   } else {
 26     while (--argc) {
 27       printf("%s:\n", *++argv);
 28       do_ls(*argv);
 29     }
 30   }
 31 }
 32 
 33 /**
 34  * list files in directory called dirname
 35  */
 36 void do_ls(char dirname[]) {
 37   DIR *dir_ptr;
 38   struct dirent *direntp;
 39 
 40   if ((dir_ptr = opendir(dirname)) == NULL) {
 41     fprintf(stderr, "ls2: cannot open %s \n", dirname);
 42   } else {
 43     while ((direntp = readdir(dir_ptr)) != NULL) {
 44       do_stat(direntp->d_name);
 45     }
 46     closedir(dir_ptr);
 47   }
 48 }
 49 
 50 void do_stat(char *filename) {
 51   struct stat info;
 52   if (stat(filename, &info) == -1) {
 53     perror(filename);
 54   } else {
 55     show_file_info(filename, &info);
 56   }
 57 }
 58 
 59 /**
 60  * display the info about filename.
 61  * the info is stored in struct at * info_p
 62  */
 63 void show_file_info(char *filename, struct stat * info_p) {
 64   char modestr[11];
 65 
 66   mode_to_letters(info_p->st_mode, modestr);
 67 
 68   printf("%s", modestr);
 69   printf("%4d ", (int)info_p->st_nlink);
 70   printf("%-8s ", uid_to_name(info_p->st_uid));
 71   printf("%-8s ", gid_to_name(info_p->st_gid));
 72   printf("%8ld ", (long)info_p->st_size);
 73   printf("%.12s ", 4 + ctime(&info_p->st_mtime));
 74   printf("%s\n", filename);
 75 }
 76 
 77 /**
 78  * utility functions
 79  */
 80 void mode_to_letters(int mode, char str[]) {
 81   strcpy(str, "----------");
 82   if (S_ISDIR(mode)) str[0] = 'd';
 83   if (S_ISCHR(mode)) str[0] = 'c';
 84   if (S_ISBLK(mode)) str[0] = 'b';
 85 
 86   if (mode & S_IRUSR) str[1] = 'r'; // 3 bits for user
 87   if (mode & S_IWUSR) str[2] = 'w';
 88   if (mode & S_IXUSR) str[3] = 'x';
 89 
 90   if (mode & S_IRGRP) str[4] = 'r'; // 3 bits for group
 91   if (mode & S_IWGRP) str[5] = 'w';
 92   if (mode & S_IXGRP) str[6] = 'x';
 93 
 94   if (mode & S_IROTH) str[7] = 'r'; // 3 bits for other
 95   if (mode & S_IWOTH) str[8] = 'w';
 96   if (mode & S_IXOTH) str[9] = 'x';
 97 }
 98 
 99 
100 #include <pwd.h>
101 
102 /**
103  * returns pointer to username associated with uid, uses getpw()
104  */
105 char * uid_to_name(uid_t uid) {
106   struct passwd * getpwuid(), *pw_ptr;
107   static char numstr[10];
108 
109   if ((pw_ptr = getpwuid(uid)) == NULL) {
110     sprintf(numstr, "%d", uid);
111     return numstr;
112   } else {
113     return pw_ptr->pw_name;
114   }
115 }
116 
117 #include <grp.h>
118 
119 /**
120  * returns pointer to group number gid, used getgrgid(3)
121  */
122 char * gid_to_name(gid_t gid) {
123   struct group * grp_ptr;
124   static char numstr[10];
125   if ((grp_ptr = getgrgid(gid)) == NULL) {
126     sprintf(numstr, "%d", gid);
127     return numstr;
128   } else {
129     return grp_ptr->gr_name;
130   }
131 }
ls2

小结:

  • ls命令:可以列出给定目录的内容;显示给定文件的属性信息。ls的使用方法,各个常用命令行选项。理解ls包括三个方面:

 如何分辨给定的目录还是文件,如何列出目录信息,如何读取并显示文件属性 

  • 文件树:Unix下磁盘上的文件和目录被组织成一颗目录树,每个节点是目录或者是文件。 
  • ls命令的工作方式与who命令相似,只是who是打开文件、读取信息指导末尾,而ls是打开目录,读取信息直到目录末尾。 
  • 目录是什么?目录如utmp一样是一个特殊文件,其内容的每一项记录是文件和目录的名字(其实这一项中还包含其他很多有用的信息),且目录文件永远不为空,因为每个目录中包含有“.”“..”两项,分别表示当前目录和上一级目录。 
  • 既然ls命令的工作原理同who相似,那么也有一套与之相应的函数:opendir、readdir、closedir、seekdir、telldir、rewinddir。这些函数与文件操作的函数功能类似。 
  • readdir读取的便是目录文件中的记录,返回的是指向当前记录的指针。记录的类型是struct direent,这个结构体定义在/usr/include/dirent.h中。 

posted on 2018-01-31 23:12  flysong  阅读(321)  评论(0编辑  收藏  举报

导航