最近学习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接口

正文:

一、系统IO
    linux系统下面提供了一套系统API来实现外设的IO操作。
 
1、文件的打开
    系统调用open( )用于打开文件,其函数原型如下所示:
  1. NAME
  2. open, creat - open and possibly create a file or device
  3.  
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8.  
  9. int open(const char *pathname, //要打开的文件的路径和文件名
  10. int flags); //打开方式
  11.  
  12. int open(const char *pathname, //要打开的文件的路径和文件名
  13. int flags, //打开方式 , 这个格式的调用,表示使用了 O_CREAT 打开方式标志。
  14. mode_t mode); //打开后文件的权限
  15.  
  16. int creat(const char *pathname, //要创建的文件的路径和文件名
  17. mode_t mode); //创建后文件的权限
    open: 打开或者创建一个文件。
                参数flags :  如果有 O_CREAT 标志,则表示如果文件存在直接打开,否则就创建新文件; mode表示创建的
文件的读、写、执行 权限, 用 8 进制指定。
  1. mode must be specified when O_CREAT is in the flags, and is ignored otherwise.
  2. creat() is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
  open使用O_CREAT标志的时候,使用第二种调用形式,必须设置mode参数; 
  creat() 函数相当于调用open 且给第二个参数传递   O_CREAT|O_WRONLY|O_TRUNC.  三个标志的按位或结果
    返回值:
            成功返回文件描述符,失败返回 -1.
    要点:
            O_RDONLY、O_WRONLY、O_RDWR 三个标志必须取其中一个,而且三个标志互斥(即 取一个且只能取一个)
    这三个标志用于open的第二个参数。
 
2、文件的读
    系统用 read 进行文件的读
  1. NAME
  2. read - read from a file descriptor
  3.  
  4. SYNOPSIS
  5. #include <unistd.h>
  6.  
  7. ssize_t read( int fd, //要读取文件的文件描述符
  8. void *buf, //读取数据存储的缓冲区
  9. size_t count); //要读取字节数

返回值:

                    成功返回读取的字节数,  返回0 表示道文件结尾。
                    失败返回-1。
 
3、 文件的写
      用 write 函数进行文件的写入。
  1. NAME
  2. write - write to a file descriptor
  3.  
  4. SYNOPSIS
  5. #include <unistd.h>
  6.  
  7. ssize_t write(int fd, //要写入文件的文件描述符
  8. const void *buf, //待写入数据的缓冲区
  9. size_t count); //要写入的字节数
  1. 返回值:
  2. 成功返回写入到字节数, 返回0 表示没有写入任何东西。
  3. 失败返回 - 1 .
 
简单的文件复制程序:
  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6.  
  7. #define BUF_LEN 1024
  8.  
  9. int main(int argc, char* argv[])
  10. {
  11. int fd_src,
  12. fd_dst;
  13. char buf[BUF_LEN];
  14. int ret;
  15. int ret_r;
  16.  
  17. if(argc < )
  18. {
  19. printf("usage: cpfile file_src file_dst\n");
  20. printf("\tfile_src:file want to copy\n");
  21. printf("\tfile_dst:file where to store\n");
  22. exit();
  23. }
  24.  
  25. fd_src=open(argv[], O_RDONLY);
  26. if(- == fd_src )
  27. {
  28. strcpy(buf,"open ");
  29. strcat(buf,argv[]);
  30. perror(buf);
  31. exit();
  32. }
  33. fd_dst=open(argv[],O_WRONLY|O_CREAT,);
  34. if(- == fd_dst )
  35. {
  36. strcpy(buf,"open ");
  37. strcat(buf,argv[]);
  38. perror(buf);
  39. exit();
  40. }
  41.  
  42. do
  43. {
  44. memset(buf,,sizeof(buf));
  45. ret_r=read(fd_src,buf,sizeof(buf) );
  46. if(- == ret)
  47. {
  48. strcpy(buf,"read ");
  49. strcat(buf,argv[]);
  50. perror(buf);
  51. exit();
  52. }
  53. ret=write(fd_dst,buf,ret_r);
  54. if(- == ret)
  55. {
  56. strcpy(buf,"write ");
  57. strcat(buf,argv[]);
  58. perror(buf);
  59. exit();
  60. }
  61. }while( ret_r != );
  62.  
  63. close(fd_src);
  64. close(fd_dst);
  65. return ;
  66. }
4、目录操作
    要对目录进行操作需要先打开目录,用 opendir 打开目录。
  1. NAME
  2. opendir - open a directory
  3.  
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <dirent.h>
  7.  
  8. DIR *opendir(const char *name); //要打开的目录的路径和目录名
    数据类型:
             DIR类型表示指向打开目录的指针,通过这个指针对目录进行操作。
    返回值:
            成功返回指向打开目录的指针,失败返回NULL。
 
5、获取目录下的文件项
    通过 readdir 来获取目录下的目录项。 readdir 分为系统调用readdir, 以及库函数readdir, 通常使用
库函数readdir。
  1. READDIR() Linux Programmers Manual READDIR()
  2. NAME
  3. readdir - read a directory
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <dirent.h>
  7.  
  8. struct dirent *readdir(DIR *dir); //要读取的目录的指针
    返回值:
            成功返回一个描述目录项的指针, 当读取到最后一个目录项的时候返回NULL, 失败也返回NULL, 
    
    目录项指针是一个数据结构体类型: struct  dirent 其定义如下:
  1. struct dirent {
  2. ino_t d_ino; /* inode number */
  3. off_t d_off; /* offset to the next dirent */
  4. unsigned short d_reclen; /* length of this record */
  5. unsigned char d_type; /* type of file */ //文件类型
  6. char d_name[]; /* filename */ //文件名
  7. };
 
下面一个简单的目录操作程序: 实现 ls 的功能
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <dirent.h>
  4. #include <stdlib.h>
  5.  
  6. int main(int argc, char* argv[])
  7. {
  8. DIR *dir=NULL;
  9. struct dirent *file=NULL;
  10.  
  11. if(argc < ) //如果没有指定要显示的目录,就显示当前目录的的文件
  12. {
  13. dir=opendir("./");
  14. if(!dir)
  15. {
  16. perror("open");
  17. exit();
  18. }
  19. else
  20. {
  21. while(file=readdir(dir))
  22. printf("%s\t",file->d_name);
  23. }
  24. putchar('\n');
  25. closedir(dir);
  26. exit();
  27. }
  28.  
  29. dir=opendir(argv[]);
  30. if(!dir)
  31. {
  32. perror("open");
  33. exit();
  34. }
  35. while(file=readdir(dir))
  36. printf("%s",file->d_name);
  37.  
  38. printf("\n");
  39. closedir(dir);
  40. return ;
  41. }
执行结果如下:
  1. [root@localhost ls]# ls
  2. main.c
  3. [root@localhost ls]# gcc -o dir main.c
  4. [root@localhost ls]# ./dir
  5. dir main.c .. .
  6. [root@localhost ls]#
6、查看某个文件是否存在
    有时需要检测某个文件是否存在。 例如复制文件的时候,既需要检测文件是否存在,存在的话就需要提醒
用户是否需要覆盖。
    通过  access( ) 来检测文件是否存在、是否可写等信息。
  1. ACCESS() Linux Programmers Manual ACCESS()
  2. NAME
  3. access - check users permissions for a file
  4. SYNOPSIS
  5. #include <unistd.h>
  6.  
  7. int access( const char *pathname, //要检查的文件路径和文件名
  8. int mode); //要检测的内容,如文件是否存在 F_OK 等
修改后的 cpfile.c 如下
  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6.  
  7. #define BUF_LEN 1024
  8.  
  9. int main(int argc, char* argv[])
  10. {
  11. int fd_src,
  12. fd_dst;
  13. char buf[BUF_LEN];
  14. int ret;
  15. int ret_r;
  16.  
  17. if(argc < ) //参数小于3个,就打印提示信息
  18. {
  19. printf("usage: cpfile file_src file_dst\n");
  20. printf("\tfile_src:which file want to copy\n");
  21. printf("\tfile_dst:file where to store\n");
  22. printf("\n\tIf the file_src and file_dst without path,"
  23. "will operation at current directory\n");
  24. exit();
  25. }
  26.  
  27. //检测目标文件是否存在
  28. if( ! access(argv[],F_OK) )
  29. {
  30. printf("%s exist,do you want to overwrite it?(y/n):",argv[]);
  31. buf[]=getchar();
  32. if( 'n' == buf[] )
  33. exit();
  34. }
  35.  
  36. fd_src=open(argv[], O_RDONLY);
  37. if(- == fd_src )
  38. {
  39. strcpy(buf,"open ");
  40. strcat(buf,argv[]);
  41. perror(buf);
  42. exit();
  43. }
  44. fd_dst=open(argv[],O_WRONLY|O_CREAT,);
  45. if(- == fd_dst )
  46. {
  47. strcpy(buf,"open ");
  48. strcat(buf,argv[]);
  49. perror(buf);
  50. exit();
  51. }
  52.  
  53. do
  54. {
  55. memset(buf,,sizeof(buf));
  56. ret_r=read(fd_src,buf,sizeof(buf) );
  57. if(- == ret)
  58. {
  59. strcpy(buf,"read ");
  60. strcat(buf,argv[]);
  61. perror(buf);
  62. exit();
  63. }
  64. ret=write(fd_dst,buf,ret_r);
  65. if(- == ret)
  66. {
  67. strcpy(buf,"write ");
  68. strcat(buf,argv[]);
  69. perror(buf);
  70. exit();
  71. }
  72. }while( ret_r != );
  73.  
  74. close(fd_src);
  75. close(fd_dst);
  76. return ;
  77. }
 
7、获取文件的属性
    linux中文件具有各种属性,有时需要获取这些文件的信息,例如 ls -l 命令会显示目录下文件的信息。
在linux中可以通过 stat、fstat、lstat 函数获取文件的相关信息。
  1. STAT() Linux Programmers Manual STAT()
  2. NAME
  3. stat, fstat, lstat - get file status
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <unistd.h>
  8.  
  9. int stat(const char *path, //要查看的文件的路径和文件名
  10. struct stat *buf); //输出参数, 用于存储文件信息的结构体指针
  11.  
  12. int fstat(int filedes, //打开的文件的文件描述符
  13. struct stat *buf); //输出参数, 用于存储文件信息的结构体指针
  14.  
  15. int lstat(const char *path, //要查看的文件的路径和文件名
  16. struct stat *buf); //输出参数, 用于存储文件信息的结构体指针

返回值:

            成功返回0, 失败返回 -1 ;
 
结构体:
  1. struct stat {
  2. dev_t st_dev; /* ID of device containing file */
  3. ino_t st_ino; /* inode number */
  4. mode_t st_mode; /* protection */
  5. nlink_t st_nlink; /* number of hard links */ //硬连接数
  6. uid_t st_uid; /* user ID of owner */ //用户ID
  7. gid_t st_gid; /* group ID of owner */ //组ID
  8. dev_t st_rdev; /* device ID (if special file) */ //特殊文件ID号
  9. off_t st_size; /* total size, in bytes */ //文件大小
  10. blksize_t st_blksize; /* blocksize for filesystem I/O */ //文件IO的块大小
  11. blkcnt_t st_blocks; /* number of blocks allocated */ //文件使用的块数目
  12. time_t st_atime; /* time of last access */ //最后访问时间
  13. time_t st_mtime; /* time of last modification */ //最后修改时间
  14. time_t st_ctime; /* time of last status change */ //最后
  15. };
    下面为为改进后的简易 ls 命令源代码: 可以显示更多的信息
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <dirent.h>
  4. #include <stdlib.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7.  
  8. #define BUF_SIZE 512
  9.  
  10. //定义一个函数解析文件信息
  11. void show_stat(char buf[] ,struct stat f_stat)
  12. {
  13. printf("File : %s\n",buf);
  14. printf("\tuser id: %d\n", f_stat.st_uid);
  15. printf("\tgroup id: %d\n",f_stat.st_gid);
  16. printf("\tfile size:%.3fK\n", . * f_stat.st_size /); //显示3位小数
  17. printf("\tfile ulink:%d\n",f_stat.st_nlink);
  18. }
  19.  
  20. //定义一个函数遍历目录
  21. void dir(const char *path)
  22. {
  23. DIR *dir=NULL; //打开的目录
  24. struct dirent *f_dir=NULL; //存储目录项
  25. char buf[]={};
  26. struct stat f_stat={}; //用来检测文件的信息
  27. int ret=;
  28.  
  29. //打开目录
  30. dir=opendir(path);
  31. if(!dir)
  32. {
  33. strcpy(buf,"acces directory:");
  34. strcat(buf,path);
  35. perror(buf);
  36. exit();
  37. }
  38.  
  39. //遍历目录
  40. while( f_dir = readdir(dir) )
  41. {
  42. //首先获取文件的路径和文件名
  43. strcpy(buf,path); //路径
  44. strcat(buf,"/"); //添加路径分割符号
  45. strcat(buf,f_dir->d_name); //文件名,buf包含路径名和文件名
  46.  
  47. //获取目录项的属性
  48. ret=stat(buf,&f_stat);
  49. if(ret)
  50. {
  51. perror(buf);
  52. }
  53.  
  54. if(S_ISDIR(f_stat.st_mode)) //如果是目录
  55. {
  56. printf("File : %s\n",f_dir->d_name);
  57. printf("\tA directory\n");
  58. }
  59. else if(S_ISREG(f_stat.st_mode))
  60. {
  61. show_stat(f_dir->d_name, f_stat);
  62. }
  63. else
  64. {
  65. printf("File : %s\n", f_dir->d_name);
  66. printf("\tother file type");
  67. }
  68. }//遍历目录结束
  69. }
  70.  
  71. int main(int argc, char* argv[])
  72. {
  73. struct stat f_stat;
  74. int ret;
  75. char buf[BUF_SIZE];
  76.  
  77. //首先判断是否有第二个参数, 没有就显示当前目录
  78. if( argc < )
  79. {
  80. dir("."); //注意这个地方,不能传递"./",因为dir函数中会添加最后一个反斜杠
  81. exit(); //显示完成就退出
  82. }
  83.  
  84. //有第二个参数
  85. ret=stat(argv[],&f_stat);
  86. if(ret)
  87. {
  88. strcpy(buf,"access ");
  89. strcat(buf,argv[]);
  90. perror(buf);
  91. exit();
  92. }
  93. if(S_ISDIR(f_stat.st_mode)) //如果是目录
  94. {
  95. dir(argv[]);
  96. }
  97. if(S_ISREG(f_stat.st_mode)) //如果是文件
  98. {
  99. show_stat(argv[],f_stat);
  100. }
  101. return ;
  102. }
 
8、改变工作目录
    应用程序执行的时候,都有一个工作目录:当前目录, 有时候需要在程序执行的时候切换当前目录到其
他目录。
    在程序中,可以通过函数改变 当前工作目录:    chdir( )
  1. CHDIR() Linux Programmers Manual CHDIR()
  2. NAME
  3. chdir, fchdir - change working directory
  4. SYNOPSIS
  5. #include <unistd.h>
  6.  
  7. int chdir(const char *path); //要切换到的工作目录
  8. int fchdir(int fd); //通过打开的文件描述符,切换到打开的文件所在的目录
    返回值:
            成功返回0, 失败返回-1 。
 
9、获取当前工作目录
    在应用程序中,有时可能会多次改变工作目录,为了跟踪应用程序的当前工作目录,可以通过函数 getcwd ( ) 来
获取当前的工作目录。
  1. GETCWD() Linux Programmers Manual GETCWD()
  2. NAME
  3. getcwd, get_current_dir_name, getwd - Get current working directory
  4.  
  5. SYNOPSIS
  6. #include <unistd.h>
  7.  
  8. char *getcwd( char *buf, //输出函数,用来存储当前路径的缓存区域
  9. size_t size); //缓存区域的大小
返回值:
        成功返回 buf, 失败返回NULL, 同时设置全局变量 error;
        如果路径大于buf的大小,那么 errno 将被设置为  ERANGE
 
Exp:  chdir.c
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <errno.h> //访问错误值代码
  5.  
  6. extern int errno;
  7. int main(void)
  8. {
  9. char* buf=NULL;
  10. int ret;
  11.  
  12. buf=(char *)malloc();
  13.  
  14. buf=getcwd(buf,);
  15. if(!buf)
  16. {
  17. if(ERANGE == errno)
  18. buf=(char *)realloc(buf,);
  19. }
  20. buf=getcwd(buf,);
  21. printf("before change directroy: %s\n\n",buf);
  22.  
  23. ret=chdir("/home/volcanol");
  24. if(ret)
  25. {
  26. perror("/home/volcanol");
  27. exit();
  28. }
  29. buf=getcwd(buf,);
  30. printf("after change directory:%s\n\n",buf);
  31.  
  32. free(buf);
  33. return ;
  34. }
 
 
二、标准库IO:  <stdio.h>
    标准库IO的特点是:  调用系统API接口实现标准库IO。标准库IO函数都是具有缓冲机制的IO接口。
 
1、printf
      printf 在输出时先将数据写入到缓冲区域,在遇到 '\n' 字符的时候才将数据从缓冲区显示到标准输出设备。
Exp:
  1. #include <stdio.h>
  2. #include <unistd.h> //to use sleep()
  3.  
  4. int main(void)
  5. {
  6. int i=;
  7.  
  8. for(i=;i<;i++)
  9. {
  10. printf("%d ",i);
  11. sleep(); //为了查看效果,才加上sleep();
  12. }
  13.  
  14. printf("\n");
  15.  
  16. return ;
  17. }

  执行的时候,可以看到 0、1、2、3、4 不是一个一个的输出,而是一起输出的。

 
    printf也会在缓冲区满的时候,输出数据。
    为了查看缓冲区满的时候printf函数输出数据,可以对缓冲区进行设置, 通过函数 setvbuf 设置缓冲的大小和缓冲
模式。
        标准输出的缓冲机制有三种:
            A:  无缓冲
            B:   行缓冲
            C:   全缓冲
    
    setvbuf( )的原型为:
  1. SETBUF() Linux Programmers Manual SETBUF()
  2. NAME
  3. setbuf, setbuffer, setlinebuf, setvbuf - stream buffering operations
  4. SYNOPSIS
  5. #include <stdio.h>
  6.  
  7. void setbuf(FILE *stream,
  8. char *buf);
  9.  
  10. void setbuffer(FILE *stream,
  11. char *buf,
  12. size_t size);
  13.  
  14. void setlinebuf(FILE *stream); //设置为行缓冲, stream 表示设置缓冲的文件
  15.  
  16. int setvbuf(FILE *stream, //要缓冲的文件,标准输出为 stdout
  17. char *buf, //缓冲区的首地址, =NULL 表示系统分配,
  18. int mode , //缓冲模式,行缓冲、全缓冲、无缓冲
  19. size_t size); //缓冲区大小
    mode 的取值由下面的宏指定:
               _IONBF unbuffered     :  无缓冲
              _IOLBF line buffered     : 行缓冲
              _IOFBF fully buffered    :全缓冲, 主要用于 文件。 
 
    其他三个函数都是调用 setvbuf 实现的,因此了解 setvbuf, 就能知道其他函数的用法。
    返回值:
            成功返回0 ;失败返回任意值,会设置errno。
 
Exp:  setvbuf.c    第一次设置为: 无缓冲模式
  1. #include <stdio.h>
  2. #include <unistd.h> //to use sleep()
  3.  
  4. int main(void)
  5. {
  6. int i=;
  7.  
  8. setvbuf( stdout, NULL , _IONBF , );
  9.  
  10. for(i=;i<;i++)
  11. {
  12. printf("%d ",i);
  13. sleep(); //为了查看效果,才加上sleep();
  14. }
  15.  
  16. printf("\n");
  17. return ;
  18. }

  程序执行的过程中: 可以看到数字一个一个的输出,而不是一起输出。

Exp: 第二次设置为缓冲区大小为1个字节,测试缓冲区满就输出
  1. #include <stdio.h>
  2. #include <unistd.h> //to use sleep()
  3.  
  4. int main(void)
  5. {
  6. int i=;
  7. char buf[]={};
  8.  
  9. /*setvbuf(stdout, NULL, _IONBF ,0);*/
  10. setvbuf(stdout, buf , _IOLBF , );
  11.  
  12. for(i=;i<;i++)
  13. {
  14. printf("%d ",i);
  15. sleep(); //为了查看效果,才加上sleep();
  16. }
  17.  
  18. printf("\n");
  19. return ;
  20. }

  可以看到数组0、1、2、3、4是一个一个的输出,而不是一起输出。

     还可以调用函数  fflush 来将数据从输出从缓冲区刷出,从而 printf 可以不必在遇到 '\n' 或者缓冲满的时候
  1. #include <stdio.h>
  2. #include <unistd.h> //to use sleep()
  3.  
  4. int main(void)
  5. {
  6. int i=;
  7. char buf[]={};
  8.  
  9. /*setvbuf(stdout, NULL, _IONBF ,0);*/
  10. /*setvbuf(stdout, buf , _IOLBF , 1);*/
  11.  
  12. for(i=;i<;i++)
  13. {
  14. printf("%d ",i);
  15. fflush(stdout);
  16. sleep(); //为了查看效果,才加上sleep();
  17. }
  18.  
  19. printf("\n");
  20. return ;
  21. }
特殊点:  
printf("%s");输出结果为 (null)
[root@localhost cpfile]# ./a.out main.c cpfile.c 
(null) exist,do you want to overwrite it?(y/n):n
 
2、scanf  
     scanf 在遇到 '\n' 时才能将数据从输入缓冲区读入。
Exp:  scanf.c
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. char ch;
  6. char ch_1;
  7. char buf[];
  8. char buf_1[];
  9.  
  10. scanf("%c%s",&ch,buf);
  11. printf("c=%c, str=%s\n",ch,buf);
  12.  
  13. scanf("%c%s",&ch_1,buf_1);
  14. printf("c=%c, str=%s\n",ch_1,buf_1);
  15. return ;
  16. }
执行结果如下:
  1. [root@localhost stdio]# vim scanf.c
  2. [root@localhost stdio]# gcc scanf.c
  3. [root@localhost stdio]# ./a.out
  4. hello world //输入 hello world 然后按下回车键
  5. c=h, str=ello
  6. c= , str=world
    从这个地方可以知道:
        scanf 函数在检测到输入 '\n' 后将数据写入到输入缓冲区; 而下一次调用的时候,会先检测缓冲区有没有
数据,如果缓冲区有数据,则直接从缓冲区域里面读取数据。 
        %c 可以读取空白字符, %s会以空白符号表示字符串读取结束,且不会将空白符从缓冲区删除。
        
        与输出的printf不一样,不能通过fflush将输入数据缓冲区的数据刷出。
Exp:   
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5. char ch;
  6. char ch_1;
  7. char buf[];
  8. char buf_1[];
  9.  
  10. scanf("%c%s",&ch,buf);
  11. printf("c=%c, str=%s\n",ch,buf);
  12.  
  13. fflush(stdin);
  14. scanf("%c%s",&ch_1,buf_1);
  15. printf("c=%c, str=%s\n",ch_1,buf_1);
  16. return ;
  17. }
执行结果如下:
[root@localhost stdio]# gcc scanf.c 
[root@localhost stdio]# ./a.out 
hello wolrd
c=h, str=ello
c= , str=wolrd      //输出结果为没有将输入数据缓冲区刷出
 
3、其他IO输出函数
    puts( ) : 不具有缓冲效果,直接输出, 即不会等到遇到 '\n' 时才输出数据。 
    gets(  ): 默认为行缓冲的输入。一次读入一行数据。
    getch( );
    putch( );
 
4、标准输入的文件操作函数
1) fopen
    用于打开一个文件,返回指向文件的文件流指针。原型如下:
  1. FOPEN() Linux Programmers Manual FOPEN()
  2. NAME
  3. fopen, fdopen, freopen - stream open functions
  4.  
  5. SYNOPSIS
  6. #include <stdio.h>
  7.  
  8. FILE *fopen(const char *path, //要打开的文件
  9. const char *mode); //打开模式
  10.  
  11. FILE *fdopen(int fildes, //已经用 open打开的文件的文件描述符
  12. const char *mode); //打开模式,必须与open的模式兼容
  13.  
  14. // 下面的函数,将 stream 文件流重定向到 重新为 path 打开的文件流
  15. FILE *freopen(const char *path,
  16. const char *mode,
  17. FILE *stream);
2) fclose
    fclose 用于关闭一个打开的文件流。
  1. FCLOSE() Linux Programmers Manual FCLOSE()
  2. NAME
  3. fclose - close a stream
  4. SYNOPSIS
  5. #include <stdio.h>
  6.  
  7. int fclose(FILE *fp);
3) fread、fwrite
    fread用于从文件流中读取数据。fwrite用于将数据写入到文件流。
  1. FREAD() Linux Programmers Manual FREAD()
  2. NAME
  3. fread, fwrite - binary stream input/output
  4. SYNOPSIS
  5. #include <stdio.h>
  6.  
  7. size_t fread(void *ptr, //存储读入数据的数据缓冲区首地址、指针
  8. size_t size, //要读取的数据块的带小
  9. size_t nmemb, //每次读取多少个数据块
  10. FILE *stream); //要读取的文件流
  11.  
  12. size_t fwrite(const void *ptr, //存储待写入数据的数据缓冲区首地址、指针
  13. size_t size, //要写入到数据块的大小
  14. size_t nmemb, //每次要写入多少个数据块
  15. FILE *stream); //要写入的文件流
   
  读取时候,需要检测是否已经到文件尾,如果到文件尾,那么需要结束读取操作,或者进行重新定位。
    A:  feof
  1. FERROR() Linux Programmers Manual FERROR()
  2. NAME
  3. clearerr, feof, ferror, fileno - check and reset stream status
  4. SYNOPSIS
  5. #include <stdio.h>
  6.  
  7. void clearerr(FILE *stream);
  8. int feof(FILE *stream); //检测是否到文件尾
  9. int ferror(FILE *stream);
  10. int fileno(FILE *stream);
    当检测到文件尾的时候,feof 返回非零值。     
 
    B: fseek
  1. FSEEK() Linux Programmers Manual FSEEK()
  2. NAME
  3. fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream
  4. SYNOPSIS
  5. #include <stdio.h>
  6.  
  7. int fseek(FILE *stream, long offset, int whence);
  8. long ftell(FILE *stream);
  9. void rewind(FILE *stream);
  10. int fgetpos(FILE *stream, fpos_t *pos);
  11. int fsetpos(FILE *stream, fpos_t *pos);
利用标准输入实现文件复制程序:  cpfile.c 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define BUF_SIZE 512
  6.  
  7. int main(int argc, char* argv[])
  8. {
  9. char buf[BUF_SIZE]={};
  10. FILE* fp_src;
  11. FILE* fp_dst;
  12.  
  13. if(argc<)
  14. {
  15. printf("usage: cpfile file_src file_dst\n");
  16. puts("\t file_src: the source file");
  17. puts("\t file_dst: the target file");
  18. exit();
  19. }
  20.  
  21. fp_src = fopen( argv[], "r");
  22. fp_dst = fopen( argv[], "w");
  23.  
  24. while( !feof(fp_src) )
  25. {
  26. memset(buf, , sizeof(buf));
  27. fread(buf, BUF_SIZE, , fp_src);
  28. fwrite(buf, BUF_SIZE, , fp_dst);
  29. }
  30.  
  31. fclose(fp_src);
  32. fclose(fp_dst);
  33. return ;
  34. }

  执行的时候,可以成功复制文件。

 
  这是本系列的第一篇,系列文章未完待续。

【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口的更多相关文章

  1. 【linux草鞋应用编程系列】_2_ 环境变量和进程控制

    一. 环境变量     应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作.     在linux中有两种方法获取环境变量,分述如下.   1.通过main函数的参数获取环境变量 ...

  2. 【linux草鞋应用编程系列】_6_ 重定向和VT100编程

    一.文件重定向     我们知道在linux shell 编程的时候,可以使用文件重定向功能,如下所示: [root@localhost pipe]# echo "hello world&q ...

  3. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

  4. 【linux草鞋应用编程系列】_4_ 应用程序多线程

    一.应用程序多线程     当一个计算机上具有多个CPU核心的时候,每个CPU核心都可以执行代码,此时如果使用单线程,那么这个线程只能在一个 CPU上运行,那么其他的CPU核心就处于空闲状态,浪费了系 ...

  5. 【linux草鞋应用编程系列】_3_ 进程间通信

    一.进程间通信        linux下面提供了多种进程间通信的方法, 管道.信号.信号量.消息队列.共享内存.套接字等.下面我们分别 介绍管道.信号量.消息队列.共享内存.        信号和套 ...

  6. 第3章 文件I/O(8)_贯穿案例:构建标准IO函数库

    9. 贯穿案例:构建标准IO函数库 //mstdio.h #ifndef __MSTDIO_H__ #define __MSTDIO_H__ #include <unistd.h> #de ...

  7. linux标准io的copy

    ---恢复内容开始--- 1.linux标准io的copy #include<stdio.h> int main(int argc,char **argv) { if(argc<3) ...

  8. Linux C++ 网络编程学习系列(1)——端口复用实现

    Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...

  9. linux makefile: c++ 编程_基础入门_如何开始?

    学习android 终究还是需要研究一下其底层框架,所以,学习c++很有必要. 这篇博客,算是linux(ubuntu) 下学习 c++ 的一个入门. 刚开始学习编程语言的时候,最好还是使用命令行操作 ...

随机推荐

  1. 浅析UPnP协议

    摘要:文章介绍了UPnP结构规范和开发流程,指出:UP nP协议使所有联网的设备实现互联,设备工作不需要传统的驱动程序,便可以实现设备间的 相互控制. 关键词:UPnP协议:开发流程:电子技术:工作 ...

  2. JavaScript中的百变大咖~this

    原文链接:http://www.jeffjade.com/2015/08/03/2015-08-03-javascript-this/ JavaScript作为一种脚本语言身份的存在,因此被很多人认为 ...

  3. vue.js组件化开发实践

    前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...

  4. Form authentication(表单认证)问题

    前言 最近在做ASP.NET MVC中表单认证时出了一些问题,特此记录. 问题 进行表单认证时,在 PostAuthenticateRequest 事件中从Cookie值中解密票据.如下: prote ...

  5. 交叉验证(Cross Validation)原理小结

    交叉验证是在机器学习建立模型和验证模型参数时常用的办法.交叉验证,顾名思义,就是重复的使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏. ...

  6. 使用Windows EFS(怎么给文件夹加密)进行文件加密

    和Windows BitLocker一样,Encrypting File System(EFS,加密文件系统)是Windows内置的一套基于公共密钥的加密机制,可以加密NTFS分区上的文件和文件夹,能 ...

  7. 如何用 js 获取table 或者其他块状标签的 宽和高

    这个比较简单,总体思想,标签标记一个id,js获取id,就能用它的属性了.介绍两种方法.请看下面代码. 第一种 <script> function width_table_all() { ...

  8. MySQL入门02-MySQL二进制版本快速部署

    在上篇文章 MySQL入门01-MySQL源码安装 中,我们介绍了MySQL源码安装的方法. 源码安装虽然有着更加灵活和更加优化等诸多优势.但源码编译安装部署的过程相对复杂,而且整个过程所花费的时间很 ...

  9. ssh整合问题总结--在添加商品模块实现图片(文件)的上传

    今天在做毕设(基于SSH的网上商城项目)中碰到了一个文件上传的需求,就是在后台管理员的商品模块中,有一个添加商品,需要将磁盘上的图片上传到tomcat保存图片的指定目录中: 完成这个功能需要两个步,第 ...

  10. lamp 环境搭建

    LAMP指的Linux(操作系统).ApacheHTTP 服务器,MySQL(数据库软件)和PHP语言 使用wampserver软件,搭建环境.如下图: 双击程序包,安装最后一步随便选择一个浏览器打开 ...