最近学习linux系统下的应用编程,参考书籍是那本称为神书的《Unix环境高级编程》,个人感觉神书不是写给草鞋看的,而是
写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻的感觉。我自己就是这样,比方说看进程间通信信号量章
节的时候,开始感觉就很迷糊,因此也就想在这里写一些文字,给和我一样的草鞋分享一些自己的学习经历(算不上经验吧)。
环境: windows7, VMware 9.0
操作系统版本: RHEL 5.5
内核版本: 2.6.18-194.el5
Gcc版本: gcc 版本 4.1.2 20080704 (Red Hat 4.1.2-48) 【2008年7月4日构建的】
【linux草鞋应用编程系列】的系列文章,欢迎批评指正。 欢迎转载,如果您愿意可以添加本系列文章的链接,即本草鞋的在博客园
的链接。
正文中的函数的原型都是通过 man page 查看和复制到,查看的时候如果与这里的不一样,请以查看的为准, 因为不同的内核
版本支持的函数,以及函数的参数可能存在一些出入。
废话少说,下面开始正题。
开篇: 系统调用IO接口与标准IO接口
正文:
NAME open, creat - open and possibly create a file or device SYNOPSIS #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, //要打开的文件的路径和文件名 int flags); //打开方式 int open(const char *pathname, //要打开的文件的路径和文件名 int flags, //打开方式 , 这个格式的调用,表示使用了 O_CREAT 打开方式标志。 mode_t mode); //打开后文件的权限 int creat(const char *pathname, //要创建的文件的路径和文件名 mode_t mode); //创建后文件的权限
mode must be specified when O_CREAT is in the flags, and is ignored otherwise. creat() is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
NAME read - read from a file descriptor SYNOPSIS #include <unistd.h> ssize_t read( int fd, //要读取文件的文件描述符 void *buf, //读取数据存储的缓冲区 size_t count); //要读取字节数
返回值:
NAME write - write to a file descriptor SYNOPSIS #include <unistd.h> ssize_t write(int fd, //要写入文件的文件描述符 const void *buf, //待写入数据的缓冲区 size_t count); //要写入的字节数
返回值: 成功返回写入到字节数, 返回0 表示没有写入任何东西。 失败返回 - 1 .
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #define BUF_LEN 1024 int main(int argc, char* argv[]) { int fd_src, fd_dst; char buf[BUF_LEN]; int ret; int ret_r; if(argc < 3) { printf("usage: cpfile file_src file_dst\n"); printf("\tfile_src:file want to copy\n"); printf("\tfile_dst:file where to store\n"); exit(0); } fd_src=open(argv[1], O_RDONLY); if(-1 == fd_src ) { strcpy(buf,"open "); strcat(buf,argv[1]); perror(buf); exit(1); } fd_dst=open(argv[2],O_WRONLY|O_CREAT,00666); if(-1 == fd_dst ) { strcpy(buf,"open "); strcat(buf,argv[2]); perror(buf); exit(1); } do { memset(buf,0,sizeof(buf)); ret_r=read(fd_src,buf,sizeof(buf) ); if(-1 == ret) { strcpy(buf,"read "); strcat(buf,argv[1]); perror(buf); exit(2); } ret=write(fd_dst,buf,ret_r); if(-1 == ret) { strcpy(buf,"write "); strcat(buf,argv[2]); perror(buf); exit(3); } }while( ret_r != 0); close(fd_src); close(fd_dst); return 0; }
NAME opendir - open a directory SYNOPSIS #include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); //要打开的目录的路径和目录名
READDIR(3) Linux Programmer’s Manual READDIR(3) NAME readdir - read a directory SYNOPSIS #include <sys/types.h> #include <dirent.h> struct dirent *readdir(DIR *dir); //要读取的目录的指针
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file */ //文件类型 char d_name[256]; /* filename */ //文件名 };
#include <stdio.h> #include <unistd.h> #include <dirent.h> #include <stdlib.h> int main(int argc, char* argv[]) { DIR *dir=NULL; struct dirent *file=NULL; if(argc < 2) //如果没有指定要显示的目录,就显示当前目录的的文件 { dir=opendir("./"); if(!dir) { perror("open"); exit(1); } else { while(file=readdir(dir)) printf("%s\t",file->d_name); } putchar('\n'); closedir(dir); exit(0); } dir=opendir(argv[1]); if(!dir) { perror("open"); exit(1); } while(file=readdir(dir)) printf("%s",file->d_name); printf("\n"); closedir(dir); return 0; }
[root@localhost ls]# ls main.c [root@localhost ls]# gcc -o dir main.c [root@localhost ls]# ./dir dir main.c .. . [root@localhost ls]#
ACCESS(2) Linux Programmer’s Manual ACCESS(2) NAME access - check user’s permissions for a file SYNOPSIS #include <unistd.h> int access( const char *pathname, //要检查的文件路径和文件名 int mode); //要检测的内容,如文件是否存在 F_OK 等
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #define BUF_LEN 1024 int main(int argc, char* argv[]) { int fd_src, fd_dst; char buf[BUF_LEN]; int ret; int ret_r; if(argc < 3) //参数小于3个,就打印提示信息 { printf("usage: cpfile file_src file_dst\n"); printf("\tfile_src:which file want to copy\n"); printf("\tfile_dst:file where to store\n"); printf("\n\tIf the file_src and file_dst without path," "will operation at current directory\n"); exit(0); } //检测目标文件是否存在 if( ! access(argv[2],F_OK) ) { printf("%s exist,do you want to overwrite it?(y/n):",argv[2]); buf[0]=getchar(); if( 'n' == buf[0] ) exit(0); } fd_src=open(argv[1], O_RDONLY); if(-1 == fd_src ) { strcpy(buf,"open "); strcat(buf,argv[1]); perror(buf); exit(1); } fd_dst=open(argv[2],O_WRONLY|O_CREAT,00666); if(-1 == fd_dst ) { strcpy(buf,"open "); strcat(buf,argv[2]); perror(buf); exit(1); } do { memset(buf,0,sizeof(buf)); ret_r=read(fd_src,buf,sizeof(buf) ); if(-1 == ret) { strcpy(buf,"read "); strcat(buf,argv[1]); perror(buf); exit(2); } ret=write(fd_dst,buf,ret_r); if(-1 == ret) { strcpy(buf,"write "); strcat(buf,argv[2]); perror(buf); exit(3); } }while( ret_r != 0); close(fd_src); close(fd_dst); return 0; }
STAT(2) Linux Programmer’s Manual STAT(2) NAME stat, fstat, lstat - get file status SYNOPSIS #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *path, //要查看的文件的路径和文件名 struct stat *buf); //输出参数, 用于存储文件信息的结构体指针 int fstat(int filedes, //打开的文件的文件描述符 struct stat *buf); //输出参数, 用于存储文件信息的结构体指针 int lstat(const char *path, //要查看的文件的路径和文件名 struct stat *buf); //输出参数, 用于存储文件信息的结构体指针
返回值:
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ //硬连接数 uid_t st_uid; /* user ID of owner */ //用户ID gid_t st_gid; /* group ID of owner */ //组ID dev_t st_rdev; /* device ID (if special file) */ //特殊文件ID号 off_t st_size; /* total size, in bytes */ //文件大小 blksize_t st_blksize; /* blocksize for filesystem I/O */ //文件IO的块大小 blkcnt_t st_blocks; /* number of blocks allocated */ //文件使用的块数目 time_t st_atime; /* time of last access */ //最后访问时间 time_t st_mtime; /* time of last modification */ //最后修改时间 time_t st_ctime; /* time of last status change */ //最后 };
#include <stdio.h> #include <unistd.h> #include <dirent.h> #include <stdlib.h> #include <sys/stat.h> #include <string.h> #define BUF_SIZE 512 //定义一个函数解析文件信息 void show_stat(char buf[] ,struct stat f_stat) { printf("File : %s\n",buf); printf("\tuser id: %d\n", f_stat.st_uid); printf("\tgroup id: %d\n",f_stat.st_gid); printf("\tfile size:%.3fK\n", 1. * f_stat.st_size /1024); //显示3位小数 printf("\tfile ulink:%d\n",f_stat.st_nlink); } //定义一个函数遍历目录 void dir(const char *path) { DIR *dir=NULL; //打开的目录 struct dirent *f_dir=NULL; //存储目录项 char buf[1024]={}; struct stat f_stat={}; //用来检测文件的信息 int ret=0; //打开目录 dir=opendir(path); if(!dir) { strcpy(buf,"acces directory:"); strcat(buf,path); perror(buf); exit(1); } //遍历目录 while( f_dir = readdir(dir) ) { //首先获取文件的路径和文件名 strcpy(buf,path); //路径 strcat(buf,"/"); //添加路径分割符号 strcat(buf,f_dir->d_name); //文件名,buf包含路径名和文件名 //获取目录项的属性 ret=stat(buf,&f_stat); if(ret) { perror(buf); } if(S_ISDIR(f_stat.st_mode)) //如果是目录 { printf("File : %s\n",f_dir->d_name); printf("\tA directory\n"); } else if(S_ISREG(f_stat.st_mode)) { show_stat(f_dir->d_name, f_stat); } else { printf("File : %s\n", f_dir->d_name); printf("\tother file type"); } }//遍历目录结束 } int main(int argc, char* argv[]) { struct stat f_stat; int ret; char buf[BUF_SIZE]; //首先判断是否有第二个参数, 没有就显示当前目录 if( argc < 2 ) { dir("."); //注意这个地方,不能传递"./",因为dir函数中会添加最后一个反斜杠 exit(0); //显示完成就退出 } //有第二个参数 ret=stat(argv[1],&f_stat); if(ret) { strcpy(buf,"access "); strcat(buf,argv[1]); perror(buf); exit(1); } if(S_ISDIR(f_stat.st_mode)) //如果是目录 { dir(argv[1]); } if(S_ISREG(f_stat.st_mode)) //如果是文件 { show_stat(argv[1],f_stat); } return 0; }
CHDIR(2) Linux Programmer’s Manual CHDIR(2) NAME chdir, fchdir - change working directory SYNOPSIS #include <unistd.h> int chdir(const char *path); //要切换到的工作目录 int fchdir(int fd); //通过打开的文件描述符,切换到打开的文件所在的目录
GETCWD(3) Linux Programmer’s Manual GETCWD(3) NAME getcwd, get_current_dir_name, getwd - Get current working directory SYNOPSIS #include <unistd.h> char *getcwd( char *buf, //输出函数,用来存储当前路径的缓存区域 size_t size); //缓存区域的大小
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> //访问错误值代码 extern int errno; int main(void) { char* buf=NULL; int ret; buf=(char *)malloc(1024); buf=getcwd(buf,1024); if(!buf) { if(ERANGE == errno) buf=(char *)realloc(buf,2048); } buf=getcwd(buf,2048); printf("before change directroy: %s\n\n",buf); ret=chdir("/home/volcanol"); if(ret) { perror("/home/volcanol"); exit(1); } buf=getcwd(buf,2048); printf("after change directory:%s\n\n",buf); free(buf); return 0; }
#include <stdio.h> #include <unistd.h> //to use sleep() int main(void) { int i=0; for(i=0;i<5;i++) { printf("%d ",i); sleep(1); //为了查看效果,才加上sleep(); } printf("\n"); return 0; }
执行的时候,可以看到 0、1、2、3、4 不是一个一个的输出,而是一起输出的。
SETBUF(3) Linux Programmer’s Manual SETBUF(3) NAME setbuf, setbuffer, setlinebuf, setvbuf - stream buffering operations SYNOPSIS #include <stdio.h> void setbuf(FILE *stream, char *buf); void setbuffer(FILE *stream, char *buf, size_t size); void setlinebuf(FILE *stream); //设置为行缓冲, stream 表示设置缓冲的文件 int setvbuf(FILE *stream, //要缓冲的文件,标准输出为 stdout char *buf, //缓冲区的首地址, =NULL 表示系统分配, int mode , //缓冲模式,行缓冲、全缓冲、无缓冲 size_t size); //缓冲区大小
#include <stdio.h> #include <unistd.h> //to use sleep() int main(void) { int i=0; setvbuf( stdout, NULL , _IONBF , 0 ); for(i=0;i<5;i++) { printf("%d ",i); sleep(1); //为了查看效果,才加上sleep(); } printf("\n"); return 0; }
程序执行的过程中: 可以看到数字一个一个的输出,而不是一起输出。
#include <stdio.h> #include <unistd.h> //to use sleep() int main(void) { int i=0; char buf[1]={}; /*setvbuf(stdout, NULL, _IONBF ,0);*/ setvbuf(stdout, buf , _IOLBF , 1); for(i=0;i<5;i++) { printf("%d ",i); sleep(1); //为了查看效果,才加上sleep(); } printf("\n"); return 0; }
可以看到数组0、1、2、3、4是一个一个的输出,而不是一起输出。
#include <stdio.h> #include <unistd.h> //to use sleep() int main(void) { int i=0; char buf[1]={}; /*setvbuf(stdout, NULL, _IONBF ,0);*/ /*setvbuf(stdout, buf , _IOLBF , 1);*/ for(i=0;i<5;i++) { printf("%d ",i); fflush(stdout); sleep(1); //为了查看效果,才加上sleep(); } printf("\n"); return 0; }
[root@localhost cpfile]# ./a.out main.c cpfile.c
(null) exist,do you want to overwrite it?(y/n):n
#include <stdio.h> int main(void) { char ch; char ch_1; char buf[32]; char buf_1[32]; scanf("%c%s",&ch,buf); printf("c=%c, str=%s\n",ch,buf); scanf("%c%s",&ch_1,buf_1); printf("c=%c, str=%s\n",ch_1,buf_1); return 0; }
[root@localhost stdio]# vim scanf.c [root@localhost stdio]# gcc scanf.c [root@localhost stdio]# ./a.out hello world //输入 hello world 然后按下回车键 c=h, str=ello c= , str=world
#include <stdio.h> int main(void) { char ch; char ch_1; char buf[32]; char buf_1[32]; scanf("%c%s",&ch,buf); printf("c=%c, str=%s\n",ch,buf); fflush(stdin); scanf("%c%s",&ch_1,buf_1); printf("c=%c, str=%s\n",ch_1,buf_1); return 0; }
[root@localhost stdio]# ./a.out
hello wolrd
c=h, str=ello
c= , str=wolrd //输出结果为没有将输入数据缓冲区刷出
FOPEN(3) Linux Programmer’s Manual FOPEN(3) NAME fopen, fdopen, freopen - stream open functions SYNOPSIS #include <stdio.h> FILE *fopen(const char *path, //要打开的文件 const char *mode); //打开模式 FILE *fdopen(int fildes, //已经用 open打开的文件的文件描述符 const char *mode); //打开模式,必须与open的模式兼容 // 下面的函数,将 stream 文件流重定向到 重新为 path 打开的文件流 FILE *freopen(const char *path, const char *mode, FILE *stream);
FCLOSE(3) Linux Programmer’s Manual FCLOSE(3) NAME fclose - close a stream SYNOPSIS #include <stdio.h> int fclose(FILE *fp);
FREAD(3) Linux Programmer’s Manual FREAD(3) NAME fread, fwrite - binary stream input/output SYNOPSIS #include <stdio.h> size_t fread(void *ptr, //存储读入数据的数据缓冲区首地址、指针 size_t size, //要读取的数据块的带小 size_t nmemb, //每次读取多少个数据块 FILE *stream); //要读取的文件流 size_t fwrite(const void *ptr, //存储待写入数据的数据缓冲区首地址、指针 size_t size, //要写入到数据块的大小 size_t nmemb, //每次要写入多少个数据块 FILE *stream); //要写入的文件流
FERROR(3) Linux Programmer’s Manual FERROR(3) NAME clearerr, feof, ferror, fileno - check and reset stream status SYNOPSIS #include <stdio.h> void clearerr(FILE *stream); int feof(FILE *stream); //检测是否到文件尾 int ferror(FILE *stream); int fileno(FILE *stream);
FSEEK(3) Linux Programmer’s Manual FSEEK(3) NAME fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream SYNOPSIS #include <stdio.h> int fseek(FILE *stream, long offset, int whence); long ftell(FILE *stream); void rewind(FILE *stream); int fgetpos(FILE *stream, fpos_t *pos); int fsetpos(FILE *stream, fpos_t *pos);
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BUF_SIZE 512 int main(int argc, char* argv[]) { char buf[BUF_SIZE]={}; FILE* fp_src; FILE* fp_dst; if(argc<3) { printf("usage: cpfile file_src file_dst\n"); puts("\t file_src: the source file"); puts("\t file_dst: the target file"); exit(0); } fp_src = fopen( argv[1], "r"); fp_dst = fopen( argv[2], "w"); while( !feof(fp_src) ) { memset(buf, 0, sizeof(buf)); fread(buf, BUF_SIZE, 1, fp_src); fwrite(buf, BUF_SIZE, 1, fp_dst); } fclose(fp_src); fclose(fp_dst); return 0; }
执行的时候,可以成功复制文件。