zoukankan      html  css  js  c++  java
  • volcanol的工控博客

      最近学习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( )用于打开文件,其函数原型如下所示:
    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);  //创建后文件的权限
        open: 打开或者创建一个文件。
                    参数flags :  如果有 O_CREAT 标志,则表示如果文件存在直接打开,否则就创建新文件; mode表示创建的
    文件的读、写、执行 权限, 用 8 进制指定。
     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.
      open使用O_CREAT标志的时候,使用第二种调用形式,必须设置mode参数; 
      creat() 函数相当于调用open 且给第二个参数传递   O_CREAT|O_WRONLY|O_TRUNC.  三个标志的按位或结果
        返回值:
                成功返回文件描述符,失败返回 -1.
        要点:
                O_RDONLY、O_WRONLY、O_RDWR 三个标志必须取其中一个,而且三个标志互斥(即 取一个且只能取一个)
        这三个标志用于open的第二个参数
     
    2、文件的读
        系统用 read 进行文件的读
    NAME
           read - read from a file descriptor
    
    SYNOPSIS
           #include <unistd.h>
    
           ssize_t read( int fd,     //要读取文件的文件描述符
                                          void *buf,  //读取数据存储的缓冲区
                              size_t count);   //要读取字节数

        返回值:

                        成功返回读取的字节数,  返回0 表示道文件结尾。
                        失败返回-1。
     
    3、 文件的写
          用 write 函数进行文件的写入。
    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
    ");
            printf("	file_src:file want to copy
    ");
            printf("	file_dst:file where to store
    ");
            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;
    }
    4、目录操作
        要对目录进行操作需要先打开目录,用 opendir 打开目录。
    NAME
           opendir - open a directory
    
    SYNOPSIS
           #include <sys/types.h>
           #include <dirent.h>
    
           DIR *opendir(const char *name);  //要打开的目录的路径和目录名
        数据类型:
                 DIR类型表示指向打开目录的指针,通过这个指针对目录进行操作。
        返回值:
                成功返回指向打开目录的指针,失败返回NULL。
     
    5、获取目录下的文件项
        通过 readdir 来获取目录下的目录项。 readdir 分为系统调用readdir, 以及库函数readdir, 通常使用
    库函数readdir。
    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);   //要读取的目录的指针
        返回值:
                成功返回一个描述目录项的指针, 当读取到最后一个目录项的时候返回NULL, 失败也返回NULL, 
        
        目录项指针是一个数据结构体类型: struct  dirent 其定义如下:
           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 */            //文件名
              };
     
    下面一个简单的目录操作程序: 实现 ls 的功能
    #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	",file->d_name);
            }
            putchar('
    ');
            closedir(dir);
            exit(0);
        }
    
        dir=opendir(argv[1]);
        if(!dir)
        {
            perror("open");
            exit(1);
        }
        while(file=readdir(dir))
            printf("%s",file->d_name);
    
        printf("
    ");
        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]# 
    6、查看某个文件是否存在
        有时需要检测某个文件是否存在。 例如复制文件的时候,既需要检测文件是否存在,存在的话就需要提醒
    用户是否需要覆盖。
        通过  access( ) 来检测文件是否存在、是否可写等信息。
    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 等
    修改后的 cpfile.c 如下
    #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
    ");
            printf("	file_src:which file want to copy
    ");
            printf("	file_dst:file where to store
    ");
            printf("
    	If the file_src and file_dst without path,"
                   "will operation at current directory
    ");
            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;
    }
     
    7、获取文件的属性
        linux中文件具有各种属性,有时需要获取这些文件的信息,例如 ls -l 命令会显示目录下文件的信息。
    在linux中可以通过 stat、fstat、lstat 函数获取文件的相关信息。
    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);    //输出参数, 用于存储文件信息的结构体指针

    返回值:    

                成功返回0, 失败返回 -1 ;
     
    结构体:
            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 */     //最后
              };
        下面为为改进后的简易 ls 命令源代码: 可以显示更多的信息
    #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
    ",buf);
        printf("	user id: %d
    ", f_stat.st_uid);
        printf("	group id: %d
    ",f_stat.st_gid);
        printf("	file size:%.3fK
    ", 1. * f_stat.st_size /1024); //显示3位小数
        printf("	file ulink:%d
    ",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
    ",f_dir->d_name);
                printf("	A directory
    ");
            }
            else if(S_ISREG(f_stat.st_mode))
            {
                show_stat(f_dir->d_name, f_stat);
            }
            else
            {
                printf("File :  %s
    ", f_dir->d_name);
                printf("	other 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;
    }
     
    8、改变工作目录
        应用程序执行的时候,都有一个工作目录:当前目录, 有时候需要在程序执行的时候切换当前目录到其
    他目录。
        在程序中,可以通过函数改变 当前工作目录:    chdir( )
    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);    //通过打开的文件描述符,切换到打开的文件所在的目录
        返回值:
                成功返回0, 失败返回-1 。
     
    9、获取当前工作目录
        在应用程序中,有时可能会多次改变工作目录,为了跟踪应用程序的当前工作目录,可以通过函数 getcwd ( ) 来
    获取当前的工作目录。
    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);    //缓存区域的大小
    返回值:
            成功返回 buf, 失败返回NULL, 同时设置全局变量 error;
            如果路径大于buf的大小,那么 errno 将被设置为  ERANGE
     
    Exp:  chdir.c
    #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
    
    ",buf);
    
        ret=chdir("/home/volcanol");
        if(ret)
        {
            perror("/home/volcanol");
            exit(1);
        }
        buf=getcwd(buf,2048);
        printf("after change directory:%s
    
    ",buf);
    
        free(buf);
        return 0;
    }
     
     
    二、标准库IO:  <stdio.h>
        标准库IO的特点是:  调用系统API接口实现标准库IO。标准库IO函数都是具有缓冲机制的IO接口。
     
    1、printf
          printf 在输出时先将数据写入到缓冲区域,在遇到 ' ' 字符的时候才将数据从缓冲区显示到标准输出设备。
    Exp:
    #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("
    ");
    
        return 0;
    } 

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

     
        printf也会在缓冲区满的时候,输出数据。
        为了查看缓冲区满的时候printf函数输出数据,可以对缓冲区进行设置, 通过函数 setvbuf 设置缓冲的大小和缓冲
    模式。
            标准输出的缓冲机制有三种:
                A:  无缓冲
                B:   行缓冲
                C:   全缓冲
        
        setvbuf( )的原型为:
    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);       //缓冲区大小
        mode 的取值由下面的宏指定:
                   _IONBF unbuffered     :  无缓冲
                  _IOLBF line buffered     : 行缓冲
                  _IOFBF fully buffered    :全缓冲, 主要用于 文件。 
     
        其他三个函数都是调用 setvbuf 实现的,因此了解 setvbuf, 就能知道其他函数的用法。
        返回值:
                成功返回0 ;失败返回任意值,会设置errno。
     
    Exp:  setvbuf.c    第一次设置为: 无缓冲模式
    #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("
    ");
        return 0;
    }

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

    Exp: 第二次设置为缓冲区大小为1个字节,测试缓冲区满就输出
    #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("
    ");
        return 0;
    }

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

         还可以调用函数  fflush 来将数据从输出从缓冲区刷出,从而 printf 可以不必在遇到 ' ' 或者缓冲满的时候
    #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("
    ");
        return 0;
    }
    特殊点:  
    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 在遇到 ' ' 时才能将数据从输入缓冲区读入。
    Exp:  scanf.c
    #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
    ",ch,buf);
    
        scanf("%c%s",&ch_1,buf_1);
        printf("c=%c, str=%s
    ",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
        从这个地方可以知道:
            scanf 函数在检测到输入 ' ' 后将数据写入到输入缓冲区; 而下一次调用的时候,会先检测缓冲区有没有
    数据,如果缓冲区有数据,则直接从缓冲区域里面读取数据。 
            %c 可以读取空白字符, %s会以空白符号表示字符串读取结束,且不会将空白符从缓冲区删除。
            
            与输出的printf不一样,不能通过fflush将输入数据缓冲区的数据刷出。
    Exp:   
    #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
    ",ch,buf);
    
        fflush(stdin);
        scanf("%c%s",&ch_1,buf_1);
        printf("c=%c, str=%s
    ",ch_1,buf_1);
        return 0;
    }
    执行结果如下:
    [root@localhost stdio]# gcc scanf.c 
    [root@localhost stdio]# ./a.out 
    hello wolrd
    c=h, str=ello
    c= , str=wolrd      //输出结果为没有将输入数据缓冲区刷出
     
    3、其他IO输出函数
        puts( ) : 不具有缓冲效果,直接输出, 即不会等到遇到 ' ' 时才输出数据。 
        gets(  ): 默认为行缓冲的输入。一次读入一行数据。
        getch( );
        putch( );
     
    4、标准输入的文件操作函数
    1) fopen
        用于打开一个文件,返回指向文件的文件流指针。原型如下:
    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);   
    2) fclose
        fclose 用于关闭一个打开的文件流。
    FCLOSE(3)                  Linux Programmer’s Manual                 FCLOSE(3)
    NAME
           fclose - close a stream
    SYNOPSIS
           #include <stdio.h>
    
           int fclose(FILE *fp);
    3) fread、fwrite
        fread用于从文件流中读取数据。fwrite用于将数据写入到文件流。
    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);    //要写入的文件流
       
      读取时候,需要检测是否已经到文件尾,如果到文件尾,那么需要结束读取操作,或者进行重新定位。
        A:  feof
    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);
        当检测到文件尾的时候,feof 返回非零值。     
     
        B: fseek
    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);
    利用标准输入实现文件复制程序:  cpfile.c 
    #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
    ");
            puts("	 file_src: the source file");
            puts("	 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;
    }

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

     
      这是本系列的第一篇,系列文章未完待续。
  • 相关阅读:
    Coding4Fun.Phone.Controls的使用
    发布windows phone应用经历实谈
    我的第一款windows phone软件
    华农js抢课神器
    zookeeper 实战案例分享:cruator客户端编程
    zookeeper学习与实战(二)集群部署
    zookeeper学习与实战(一)环境部署
    Flask框架的学习与实战(三):登陆管理
    Flask框架的学习与实战(二):实战小项目
    Flask框架的学习与实战(一):开发环境搭建
  • 原文地址:https://www.cnblogs.com/volcanol/p/3471759.html
Copyright © 2011-2022 走看看