1-3 列出一个目录中的所有文件
#include "apue.h"
#include "dirent.h"
int main(int argc,char *argv[])
{
DIR *dp; //定义了一个DIR 结构体变量
struct dirent *dirp; //定义了一个dirent 结构体变量
if(argc !=2)
err_quit("usage: ls directory_name");
if(dp=opendir(argv[1])==NULL)
err_sys("can't open %s",argv[1]);
while((dirp = readdir(dp))!=NULL)
printf("%s\n",dirp->d_name);
closedir(dp);
exit(0);
}
DIR结构体的定义:
struct __dirstream
{
void *__fd;
char *__data;
int __entry_data;
char *__ptr;
int __entry_ptr;
size_t __allocation;
size_t __size;
__libc_lock_define (, __lock)
};
typedef struct __dirstream DIR;
dirent结构体的定义:
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */
}
参考了Linux下DIR,dirent,stat等结构体详解
1-4 将标准输入复制到标准输
#include "apue.h"
#define BUFFSIZE 4096
int main(void)
{
int n;
char buf[BUFFSIZE];
while (n=read(STDIN_FILENO,buf, BUFFSIZE) > 0 ) //read函数:读取STDIN_FILENO(标准输入)的数据储存到字符串buf中,大小为BUFFSIZE,并返回读取的字符大小
if(write(STDOUT_FILENO,buf,n) !=n) //write函数类似于read函数
err_sys("write error");
if(n<0)
err_sys("read error");
exit(0);
}
文件描述符:内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
注意:read、write提供的是不带缓冲的I/O,使用的是文件描述符
类似的还有:open、lseek、close
1-5 使用标准I/O讲标准输入复制到标准输出
#include "apue.h"
int main()
{
int c;
while((c = getc(stdin)) != EOF) //getc函数:从文件指针stdin指向的文件流中读取一个字符,并把它作为函数值返回给整型变量c,并把位置标识符往前移动,读入字符不成功则返回值为EOF。
if(putc(c,stdout) == EOF) //putc函数:在stdout所指向的文件的当前读写位置写入一个字符。写入字符成功则函数返回值为该字符的ASCII值,写入字符不成功则返回值为EOF。
err_sys("output error");
if(ferror(stdin))
err_sys("input error");
exit(0);
}
注:和不带缓冲的I/O函数比较起来,带缓冲的I/O不用定义BUFFSIZE大小,并不用在输入函数中接入参数表示大小
1-6 打印进程ID
#include "apue.h"
int main(void)
{
printf("Hello world from process ID %ld\n",(long)getpid); //getpid函数:功能是取得进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
exit(0);
}
1-7 从标准输入读命令并执行
#include "apue.h"
#include "sys/wait.h"
int main(void)
{
char buf[MAXLINE]; //定义于apue.h
pid_t pid;
int status;
printf("%% "); //打印出%
while(fgets(buf, MAXLINE, stdin) !=NULL)
{
if(buf[strlen(buf)-1]=='\n')
buf[strlen(buf)-1]=0; //由于execlp函数需要的字符串以NULL(0)结尾,把'\n'换成0
if(pid = fork() < 0)
err_sys("fork error");
else if(pid==0)
{
execlp(buf, buf, (char *)0);
err_ret("couldn't execute: %s",buf);
exit(127);
}
if((pid = waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%%");
}
exit(0);
}
execlp函数的百度百科解释:
execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则它将解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了.
1-8 示例strerror 和 perror
#include "apue.h"
#include "errno.h"
int main(int argc, char *argv[])
{
fprintf(stderr,"EACCES: %s\r", strerror(EACCES)); //stderr是标准错误,不会把数据放到缓冲区,而是直接输出!
errno = ENOENT; //ENOENT一般是没找到文件或路径,包括因为权限问题没找到的情况。
perror(argv[0]);
exit(0);
}
疑惑:
不清楚EACCES是什么东西
1-9打印出用户ID和组ID
#include "apue.h"
int main(void)
{
printf("uid = %d, gid = %d\n",getuid(),getgid());
exit(0);
}
1-10 在1-7的基础上,捕获退出的信号
#include "apue.h"
#include "sys/wait.h"
static void sig_int(int); //信号捕获函数
int main(void)
{
char buf[MAXLINE]; //定义于apue.h
pid_t pid;
int status;
if(signal(SIGINT, sig_int) == SIG_ERR)
err_sys("signal error");
printf("%% "); //打印出%
while(fgets(buf, MAXLINE, stdin) !=NULL)
{
if(buf[strlen(buf)-1]=='\n')
buf[strlen(buf)-1]=0; //由于execlp函数需要的字符串以NULL(0)结尾,把'\n'换成0
if(pid = fork() < 0)
err_sys("fork error");
else if(pid==0)
{
execlp(buf, buf, (char *)0);
err_ret("couldn't execute: %s",buf);
exit(127);
}
if((pid = waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%%");
}
exit(0);
}
void sig_int(int signo)
{
printf("interrupt\n%% ");
}