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


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 null
begin errno = 0
after errno = 2
open: No such file or directory

$ ./a.out hello 
begin errno = 0
fd = 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 
$ ls
a.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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值