1.文件IO函数练习及注意事项

来源:互联网 发布:java解压包的后缀 编辑:程序博客网 时间:2024/05/01 19:27

Demo 1 open.c 创建文件

  #include <sys/types.h>  #include <sys/stat.h>  #include <fcntl.h>  #include <unistd.h>  #include <stdio.h>  int main(void)  {          int fd;          fd = open("hello", O_CREAT | O_RDWR, 0644);          printf("fd = %d\n", fd);          close(fd);          return 0;}--------------------------------------------------$ ./a.out fd = 3

O_CREAT | O_RDWR: 按位或
O_CREAT 八进制:00000100 二进制 001 000 000
O_RDWR 八进制: 00000002 二进制 000 000 010
按位或 前面零省略 001 000 010
注意:

  • 如果创建一个新文件的时候没有mode位,系统会自动填充乱码,但不会报错;当打开一个已有文件的时候,不用mode参数.

Demo 2 error.c 出错码

#include <sys/types.h>                                 #include <sys/stat.h>                                  #include <fcntl.h>                                     #include <unistd.h>                                    #include <errno.h>                                     #include <stdio.h>                                     #include <stdlib.h>                                    extern int errno; //外部变量引用                       int main(int argc, char *argv[])                       {                                                              int fd;                                                if(argc < 2) {                                                 printf("./a.out filename\n");                          return -1;                                     }                                                      printf("begin errno = %d\n", errno);                   fd = open(argv[1],  O_RDWR);                           if(fd < 0) {                                                   printf("after errno = %d\n", errno);                   perror("open");                                        exit(0);                                       }                                                      printf("fd = %d\n", fd);                               close(fd);                                             return 0;                                      }                                                      ---------------------------------------$ ./a.out ./a.out filename$ ./a.out nullbegin errno = 0after errno = 2open: No such file or directory$ ./a.out hello begin errno = 0fd = 3

注意:

  • errno这个出错时设置相应的值,但是成功是不会置为0,所以要注意:
fd1 = open("hello",  O_RDWR); fd2 = open("world",  O_RDWR);         if(fd < 0) {                 printf("errno = %d\n", errno);                 perror("open");                 exit(0);         }

在上面的函数中,如果hello打开失败,world打开成功,打印出来的是errno是打开”hello”出错时对应的值,而不会因为打开”world”成功置为0;所以在使用perror的时候一定要紧跟要你想打印出错原因的函数,中间不要有其他可以设置errno的函数;

Demo 3 输出重定向 re_printf.c

#include <sys/stat.h>                              #include <sys/types.h>                             #include <sys/fcntl.h>                             #include <stdio.h>                                 #include <unistd.h>                                #include <stdlib.h>                                int main(void)                                     {                                                          int fd;                                            close(STDOUT_FILENO);                              fd = open("hello", O_CREAT|O_RDWR, 0644);          if(fd < 0){                                                perror("open");                                    exit(0);                                   }                                                  printf("Nice to meet you!\n");                     fflush(stdout);                                    close(fd);                                         return 0;                                  }                                                  -----------------------------------------$ ./a.out $ lsa.out  hello  re_printf.c$ cat hello Nice to meet you!

程序运行流程:开始把stdout(标准输出)这个文件关掉了,打开了“hello”,那这个时候“hello”的文件描述符就是1,fd = 1;但是printf不知道1这个文件描述符对应的文件改变了,他还是把“Nice to meet you\n”写到了C标准库的缓冲区,然后等缓冲区刷新的时候写到1这个文件描述符对应的磁盘文件当中去

注意:

  • fflush的作用:如果不使用fflush,文件缓冲区不刷新,但是close(fd)已经把1这个文件描述符关闭掉了,那数据就写不到1所对应的磁盘文件当中了
  • 如果把fflush和close都去掉,那当程序运行到return 0的时候,系统还是会刷新缓冲区,把文件写到磁盘当中去,exit(0)也是可以的,或者main没有返回值,return和什么都不写也都是可以的。

Demo 4 测试文件描述符的最大值 maxfile_no.c

 #include <stdio.h>                                            #include <sys/stat.h>                                         #include <sys/types.h>                                        #include <fcntl.h>                                            #include <stdlib.h>                                           #include <unistd.h>                                           int main(void)                                                {                                                                     int fd, i = 3;                                                char filename[100];                                           while(1) {                                                            printf("i = %d\n", i);                                        sprintf(filename, "file%d", i);                               fd = open(filename, O_CREAT|O_RDWR, 0644);                    if(fd < 0){                                                           perror("open");                                               exit(-1);                                             }                                                             i++;                                                  }                                                     }                                                            

Demo 5 mycp.c 复制文件

#include <stdlib.h>                                       #include <stdio.h>                                        #include <sys/stat.h>                                     #include <sys/types.h>                                    #include <fcntl.h>                                        #include <unistd.h>                                       #define BUFFER_SIZE 4096                                  void sys_err(const char *buf, int status)                 {                                                                 perror(buf);                                              exit(status);                                     }                                                         int main(int argc, char *argv[])                          {                                                                 int fdsrc, fddest, len;                                   char buf[BUFFER_SIZE] = "0";                              if(argc < 3) {                                                    printf("./a.out fdsrc fddest\n");                         exit(0);                                          }                                                         fdsrc = open(argv[1], O_RDONLY);                          if(fdsrc < 0)                                                     sys_err("open fdsrc", 1);                         fddest = open(argv[2], O_CREAT | O_WRONLY, 0664);         if(fddest < 0)                                                    sys_err("open fdsrc", 2);                         while((len = read(fdsrc, buf, sizeof(buf))) > 0) {                if(write(fddest, buf, len) < 0)                                   sys_err("write", 3);                      }                                                         if(len < 0)                                                       sys_err("read", 4);                               close(fdsrc);                                             close(fddest);                                            return 0;                                         }  -----------------------------$ ./a.out hello world

注意:在write的时候count一定要写read的返回值,而不是buf的大小;避免如果读的文件长度小于buf的长度的时候,把垃圾数据写入到文件中,read的返回值就是每次读到数据的大小

Demo 6 block.c 阻塞的情况

#include <sys/stat.h>                       #include <sys/types.h>                      #include <unistd.h>                         int main(void)                              {                                                   int len;                                    char buf[10];                               len = read(STDIN_FILENO, buf, 10);          write(STDOUT_FILENO, buf, len);             return 0;                           }                                           

Demo 7 noblock.c 非阻塞情况

#include <sys/stat.h>                                                   #include <fcntl.h>                                                      #include <stdlib.h>                                                     #include <sys/types.h>                                                  #include <unistd.h>                                                     #include <errno.h>                                                      #include <string.h>                                                     #define MSG_TRY "try again\n"                                           int main(void)                                                          {                                                                               int len;                                                                char buf[10];                                                           int fd = open("/dev/tty", O_RDWR|O_NONBLOCK);                           //int fd = open(STDIN_FILENO, O_RDWR|O_NONBLOCK);                       if(fd < 0) {                                                                    perror("open /dev/tty");                                                exit(0);                                                        }                                                               tryagain:                                                                       len = read(fd, buf, 10);                                                if(len < 0) {                                                                   if(errno == EAGAIN) {                                                           write(STDOUT_FILENO, MSG_TRY,strlen(MSG_TRY));                          sleep(1);                                                               goto tryagain;                                                  }                                                                       perror("read");                                                         exit(1);                                                        }                                                                       if(write(STDOUT_FILENO, buf, len) < 0) {                                        perror("write");                                                        exit(2);                                                        }                                                                       close(fd);                                                              return 0;                                                       }                                                       

注意:

  • 这次调用的不是STDIN_FILENO这个文件了,而是“/dev/tty”这个文件,因为我们要给文件重新修改flags属性,但是STDIN_FILENO已经打开过了,没有办法在修改flags,“/dev/tty”这个文件是当前终端,也可以接收终端的输入;
  • 当文件是非阻塞文件的时候,去读这个文件,读不到值的出错码就是EAGAIN,所以当errno等于EAGAIN的时候,就需要再次去读这个文件,知道读到内容或出现其他出错码
  • 阻塞和非阻塞属性是跟文件属性绑定的。

Demo 7 noblock_timeout.c 非阻塞读终端加上等待超时

#include <stdio.h>                                                      #include <sys/stat.h>                                                   #include <sys/types.h>                                                  #include <fcntl.h>                                                      #include <string.h>                                                     #include <unistd.h>                                                     #include <stdlib.h>                                                     #include <errno.h>                                                      #define MSG_TRY "try again\n"                                           #define MSG_TIMEOUT "timeout\n"                                         void sys_err(const char *buf, int status)                               {                                                                               perror(buf);                                                            exit(status);                                                   }                                                                       int main(void)                                                          {                                                                               int fd, i, len;                                                         char buf[10];                                                           fd = open("/dev/tty", O_RDWR|O_NONBLOCK);                               if(fd < 0)                                                                      sys_err("open", 1);                                             for(i = 0; i < 5; i++) {                                                        len = read(fd, buf, 10);                                                if(len >= 0)                                                                    break;                                                          if(errno == EAGAIN) {                                                           write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));                         sleep(1);                                                               continue;                                                       }                                                                       sys_err("read", 2);                                             }                                                                       if(i == 5) {                                                                    write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));         }                                                                       else                                                                            write(STDOUT_FILENO, buf, len);                                 close(fd);                                                              return 0;                                                       }                                                           

注意:

  • 一定要把判断len>=0;放到判断errno == EAGAIN前面;因为errno的值不会因为read返回一个大于0的值而重置,会一直是上一次的错误值;因为errno的值不会因为read返回一个大于0的值而重置,会一直是上一次的错误值;因为errno的值不会因为read返回一个大于0的值而重置;
    重要事情说三遍!!!

Demo 8 lseek.c 指针调用

#include <sys/stat.h>                                                 #include <sys/types.h>                                                #include <fcntl.h>                                                    #include <unistd.h>                                                   #include <stdlib.h>                                                   #include <string.h>                                                   #define BUFFER "hello world\n"                                        void sys_err(const char *buf, int status)                             {                                                                             perror(buf);                                                          exit(status);                                                 }                                                                     int main(void)                                                        {                                                                             int fd, len;                                                          char buf[100];                                                        fd = open("hello", O_CREAT|O_RDWR, 0644);  //打开文件                 if(fd < 0)                                                                    sys_err("open", 0);                                           if(write(fd, BUFFER, strlen(BUFFER)) < 0)  //把数据写入文件                   sys_err("write1", 1);                                         if(lseek(fd, 0, SEEK_SET) < 0) //把文件指针重新直到文件开头                   sys_err("lseek", 0);                                          len = read(fd, buf, sizeof(buf));  //读文件                           if(len < 0)                                                                   sys_err("read", 2);                                           if(write(STDOUT_FILENO, buf, len) < 0)                                        sys_err("write2", 3);                                        return 0;                                                     }                                                                     

Demo 9 ex_lseek.c 生成大文件

#include <sys/stat.h>                                             #include <stdio.h>                                                #include <sys/types.h>                                            #include <fcntl.h>                                                #include <unistd.h>                                               #include <stdlib.h>                                               int main(int argc, char *argv[])                                  {                                                                         int fd;                                                           if(argc < 2) {                                                            printf("./a.out file");                                           return 0;                                                 }                                                                 fd = open(argv[1], O_CREAT|O_RDWR, 0644);                         if(fd < 0) {                                                              perror("open");                                                   exit(0);                                                  }                                                                 lseek(fd, 1024*10, SEEK_SET);  // 向后值1yi024*10个Byte           write(fd, "a", 1);  //然后写一个数据                              close(fd);                                                        return 0;                                                 }                                                                

注意:

  • 指针向后指完之后,一定要写入一个数据,这样文件才会保存成相应大小,如果不写数据,文件还是为空。

Demo 10 ex2_lseek.c 得到文件的大小

#include <sys/stat.h>                              #include <stdio.h>                                 #include <sys/types.h>                             #include <fcntl.h>                                 #include <unistd.h>                                #include <stdlib.h>                                int main(int argc, char *argv[])                   {                                                          int fd, len;                                       if(argc < 2) {                                             printf("./a.out file");                            return 0;                                  }                                                  fd = open(argv[1], O_CREAT|O_RDWR, 0644);          if(fd < 0) {                                               perror("open");                                    exit(0);                                   }                                                  len = lseek(fd, 0, SEEK_END);                      printf("len = %d\n", len);                         close(fd);                                         return 0;                                  }                                                  

lseek的返回值是移动后指针距离文件开头多少个Byte,由此可以得出文件的大小

Demo 10 fcntl.c 用fcntl重新实现非阻塞

#include <stdlib.h>                                                             #include <sys/stat.h>                                                           #include <sys/types.h>                                                          #include <fcntl.h>                                                              #include <errno.h>                                                              #include <unistd.h>                                                             #include <stdio.h>                                                              #include <string.h>                                                             #define MSG_TRY "try again\n"                                                   #define MSG_TIMEOUT "timeout\n"                                                 extern int errno;                                                               void sys_err(const char *buf, int status)                                       {                                                                                       perror(buf);                                                                    exit(status);                                                           }                                                                               int main(void)                                                                  {                                                                                       int fd, len, flags, i;                                                          char buf[100];                                                                  flags = fcntl(STDIN_FILENO, F_GETFL);                                           flags |= O_NONBLOCK;                                                            if(fcntl(STDIN_FILENO, F_SETFL, flags) < 0)                                             sys_err("fcntl", 1);                                                    for (i = 0; i < 5; i++) {                                                               len = read(STDIN_FILENO, buf, sizeof(buf));                                     if(len >= 0)                                                                            break;                                                                  if(errno == EAGAIN) {                                                                   write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));                                 sleep(1);                                                                       continue;                                                               }                                                                               sys_err("read", 1);                                                     }                                                                               if(i == 5)                                                                              write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));                 else                                                                                    write(STDOUT_FILENO, buf, len);                                         return 0;                                                               }                                                                               

注意:

  • 读取文件的flags用F_GETFL,写入用F_SETFL,修改flags用位或操作
0 0