File IO for Linux system programming

File IO for Linux system programming

The first day of file IO

Standard IO
open file: FILE* fopen (file name string, open mode)
rwa r+ w+ a+
(text file, binary file)
close file: fclose (FILE* p);
read a character: int fgetc (FILE* P);
Write a character: fputc(int c,FILE* P)
Read a string: fgets(char* buf,int size,FILE*)
Write a string: fputs(char* p,FILE* P);
char arr[4 ] = “abc” char* p = “abc”; (Complete memorizing the four memory areas - Jiang Yang) Binary
reading: fread (void* buf, size of each block, number of blocks, file pointer);
Binary writing: fwrite (void*buf, size of each block, number of blocks, file pointer)
Formatted reading: int fscanf(FILE *stream, const char *format, …); Similar to scanf
formatted writing: int fprintf(FILE *stream, const char *format, …); Similar to printf
file offset: fseek, rewind, ftell
(calloc, realloc) malloc -->memset() bzero( )

1. Basic concepts of standard IO

1.1c language function (c library function) is called to implement a certain function (API)

       POSIX:可移植操作系统接口,软件需要在linux下运行,API关联的标准的总称

1.2 System call: Program interface in the kernel, the middle layer between applications and hardware devices

   1> 文件操作系统调用: 打开文件,关闭文件,读写
   2> 进程控制系统调用: 创建进程 关闭进程 ps -aux   
   3> 通信类控制系统调用: 发送消息,接受消息  socket套接字
   4> 设备管理系统调用: 打开设备 关闭设备
   5> 信息维护类系统嗲用:用户程序和操作系统之间的信息

1.3 Basic concepts of files

   文件:一组相关数据的集合,  文件名:集合的名称

1.4 File classification *

    普通文件:touch 文件
    目录文件: mkdir 目录名
    设备文件: 放在dev目录下,和普通文件一样
    字符文件: sudo mknod 字符设备名 c 主编号 次编号
    块  设 备:  sudo mknod 字符设备名 b 主编号 次编号 
    管道设备:  sudo mknod 管道设备名 p 主编号 次编号
    网络设备:  sudo mknod 网络设备名 s 主编号 次编号
    链接文件: 理解成快捷方式
        软连接:ln -s 被连接文件名 新文件名 ( 是保存了被连接文件的绝对路径,是另外一个新的文件,访问时用被连接文件的路径替换)
        硬链接:ln     被连接文件名 新文件名  (普通文件没区别,指向硬盘的同一块区域)快捷方式
       删除对应的被链接文件,软连接会受到影响,而硬链接不会。

1.5 File pointer FILE* (the difference between standard IO and file IO)

   typedef struct _iobuf{
         char* ptr ;   //下一个字符的位置
         int     cnt    //剩余字节数
         int*  base;  // 缓冲区的位置
         int  fd ;      // 文件描述符 (文件的标志)
         int flag ;     //文件的访问模式
   }  FILE

File descriptor: is a non-negative integer and is an index pointing to the record of open files maintained by the kernel for each process.
Three default open streams: stdin (0) input stream stdout (1) output stream stderr (2) standard error stream

1.6 Conversion of file descriptors and file pointers*

    #include <stdio.h>
    函数原型:FILE *fdopen(int fd, const char *mode);
    函数作用:把fd的文件描述符转换成文件指针,当文件IO中打开文件,需要用标准IO中的函数时需要使用。
    函数参数:fd  文件描述符    mode打开模式   
    返 回  值:文件指针。
练习:找到标准输入的 文件指针。
 #include <stdio.h>
 #include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
   FILE * file = fopen("abc","r");
   FILE* p = fdopen(0,"r");
  if(p)
 {
    printf("p = %p\n",p);
 }
if(file == NULL)
 {
    //perror("fdopen");
    printf("%s\n",strerror(errno));
    exit(0);
   }
  return  0;
 }
  
    函数原型: int fileno(FILE *stream);
    函数作用:文件指针转换成文件描述符。
    函数参数:stream 是文件指针   
    返 回  值:文件描述符。
    使用:  标准io打开的文件fopen,用read去读取或者write写需要文件描述符,需要进行转换。

2. File IO

2.1 Open file*

   #include <sys/types.h>
   #include <sys/stat.h>
   #include <fcntl.h>

  函数原型  int open(char *pathname, int flags, mode_t mode);
  函数参数:pathname 文件名或者文件路径
                   flags         打开模式
                   mode       只有创建时候使用 文件创建权限0666
  作      用: 打开文件
  返 回  值: 文件描述符,也是文件的打开标志,失败返回-1; 
  打开模式:
      第一组: 只读打开   O_RDONLY
                     只写方式:O_WRONLY
                     读写方式:O_RDWR
      第二组:  O_CREAT 创建文件,如果文件不存在则创建,需要和mode一起配合使用,mode的创建时候的文件权限
                     O_APPEND 追加的方式写入文件,如果文件已经有内容了,则在文件末尾添加内容,不会覆盖,文件末尾开始读不到内容。
        O_TRUNC 覆盖写,每一次写都会把原有内容 清空。

2.2 File closing *

    函数原型: int close(int fd);
    头文件:  #include <unistd.h>
    作用: 关闭文件
    返回值: 是否成功,如果是0则关闭成功 -1关闭失败

   练习:创建danny.log文件  提示3秒后关闭
    #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("danny.log",O_RDWR| O_CREAT,0666);
if(fd == -1)
{
    printf("%s\n",strerror(errno));
    return 0;
}
sleep(1);
printf("倒计时1妙\n");
sleep(2);
close(fd);
} 

2.3 File reading and writing*

     #include <unistd.h>
   函数原型:  ssize_t read(int fd, void *buf, size_t count);
   函数参数: fd 文件描述符
                     buf  存放读取内容的缓存。(数组,malloc申请空间)
                     count:从文件中读取的字节数
   返回值:如果成功返回实际读取的字节数   如果失败返回-1,文件末尾返回0;
  
   函数原型: int write(int fd, const void *buf, long count);
   头  文  件: #include <unistd.h>
   作       用: 写入文件内
    参       数:  fd 文件描述符
                     buf  存放读取内容的缓存。(数组,malloc申请空间)
                     count:从文件中读取的字节数
   返回值:如果成功返回实际写入的字节数
               失败返回-1 错误信息错入errno

   练习:文件拷贝功能:./cp 文件1  文件2    (实现cp命令)

2.4 File offset*

     #include <sys/types.h>
    #include <unistd.h>

   函数原型:off_t lseek(int fd, off_t offset, int whence);
   作      用: 移动光标,移动文件偏移位置。
   参      数:whence    SEEK_CUR 从当前位置为餐卡偏移
                                   SEEK_SET  从文件头开始偏移
                                   SEEK_END  从文件尾开始偏移
                 offset:偏移多少,正数或者负数,正数往右,负数往
   注     意: socket文件--网络设备文件,管道文件没法移动,

2.5 File permissions *

      函数原型:  int access(const char *pathname, int mode);
      头  文  件: #include <unistd.h>
      参       数: *pathname,文件名  ,mode 用来判断某一个模式
                        mode格式如下:
                        R_OK     判断文件是否有可读权限
                        W_OK    可写权限
                        F_OK      文件是否存在
                        X_OK       判断文件是否可执行
       返回值:如果是0则表示成功。失败返回-1  错误信息存入errno中
       练习:判断参数中的文件是否存在,如果存在判断有可执行权限

2.6 Delete files*

   函数原型:int remove(const char *pathname);
   头文件:  stdio.h
   作用: 删除文件
    返回值:如果成功返回0 失败返回-1  errno
    如果pathnam是目录,则需要调用rmdir()处理。
    如果pathname是文件,则会调用unlink()处理

2.7 fcntl function*

  函数原型: int fcntl(int fd, int cmd, ... /* arg */ );
  头 文 件:  #include <unistd.h>         #include <fcntl.h>
  参      数:  fd  文件描述符
                    cmd 命令
                   F_DUPFD      赋值文件描述符
                   F_GETFD      获取文件描述符标志
                   F_SETFD       修改文件描述符
                   F_GETFL       获取文件的状态标志
                   F_SETFL        设置文件的状态标志
                   F_GETLK       获取文件锁
                   F_SETLK        设置文件锁
                   F_GETOWN   获取信号处理
                   F_SETOWN    设置信号处理

                 第三个:操作命令的参数,比如说设置文件描述符,设置成多少需要用第三个
   返回值:如果是错误  返回-1
                返回文件描述符    返回文件锁   返回状态标志  


第一个重点:  文件状态获取和设置(可读可写)
      获取状态标志:通过第二个参数 F_GETFL 来获取到现有的状态标志。例如O_REDONLY  ,O_WRONLY, O_RDWR,然后用int变量接受,则得到的属性存入到了int中,
	把得到的返回值和某一个属性例如O_REONLY进行按位与操作     
     增加状态标志: 通过第二个参数F_SETFL来设置,第三个参数是设置的内容,我们可以通过 返回值 |= 你想为期增设的标志,最后调用fcntl函数保存标志。
     删除状态标志:      通过第二个参数F_SETFL来设置,第三个参数是设置的内容,我们可以通过 返回值 &=你想为期增设的标志的~来设置,最后调用fcntl函数保存标志。

     第二个重点 :设置IO设备非堵塞  F_SETFL
     设置: O_NONBLOCK 属性。
     第一种设置方式: 在open的时候添加非堵塞属性  
     第二种设置方式:使用fcntl函数添加非堵塞属性。
 
第三个重点:设置文件锁 F_SETLK    F_GETLK
     对文件枷锁后,只允许一个进程读写,其他进程等待读写,直到解锁。
      struct flock {
           ...
           short l_type;    /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */
           short l_whence;  /*偏移量的起始位置,枷锁的参考位置  SEEK_SET, SEEK_CUR, SEEK_END */
           off_t l_start;   /* 正数表示往后偏移后枷锁, */
           off_t l_len;     /* 枷锁多少个字节 */  如果字节数为0默认为偏移位置到文件结束。
           pid_t l_pid;     /* 锁的进程id号
             ...
       };
   代码:先定义机构体,给结构体成员赋值,fcntl(fd,F_SETLK,&结构体);
   struct flock  lock;
   lock.type =F_RDLCK;
   lock.whence = SEEK_SET;
   lock.start = 3;
   lock.len = 0;
   fcntl(fd,F_SETLK,&lock); 

File IO the next day

one,

  1. Buffer: Standard IO has a buffer. The input and output data are first put into the cache. When the cache is full or the cache encounters \n, it will be refreshed and the data will be refreshed to the screen.
    #include <stdio.h>
    int fflush(FILE *stream);
    Function: To refresh the cache area, you need to use FILE, because file IO does not have a cache area, you can refresh the input cache or output cache, such as fflush(stdout);

Introduced: open uses creation attribute O_CREAT, 0666

1. Create files [Key points]

  函数原型: int creat(const char *pathname, mode_t mode);
  头文件:#include <sys/types.h>     
                 #include <sys/stat.h>   #include <fcntl.h>

  参数:pathname 文件名/文件路径  
            mode   创建模式  0666
  先从终端 输入一个文件名,如果文件存在则打印存在,如果不存在则创建文件。   ./a.out  danny.txt   
    练习:从终端输入文件名的参数,先判断文件是否存在,如果不存在则创建。

2. fcntl file locking

      对文件枷锁后,只允许一个进程读写,其他进程等待读写,直到解锁。
      struct flock {
           ...
           short l_type;    /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */
           short l_whence;  /*偏移量的起始位置,枷锁的参考位置  SEEK_SET, SEEK_CUR, SEEK_END */
           off_t l_start;   /* 正数表示往后偏移后枷锁, */
           off_t l_len;     /* 枷锁多少个字节 */  如果字节数为0默认为偏移位置到文件结束。
           pid_t l_pid;     /* 锁的进程id号
             ...
       };
   代码:先定义机构体,给结构体成员赋值,fcntl(fd,F_SETLK,&结构体);
   struct flock  lock;
   lock.type =F_RDLCK;
   lock.whence = SEEK_SET;
   lock.start = 3;
   lock.len = 0;
   fcntl(fd,F_SETLK,&lock); 

2. Time function

1. Function prototype: time_t time(time_t *); [Key Points]

     参      数:   timt_t为	long int类型 的指针  或者NULL
     返 回 值:从公元1970年1月1号UTC 0点0分0秒到现在的秒数。

2. Function prototype: char *ctime(const time_t *); [Key points]

       参      数: time_t 是从1970年1月1号0点到现在的时间  time();
       返回值:  时间字符串信息,本地时间的日期和事件
       作用:获取本地时间,会自动在时间字符串后面加 \r \n自动换行

3. Function prototype: struct tm *gmtime(const time_t *);

   作用:转换成真实世界所使用的时间和日期表示方式,返回给tm结构体
   参数: time_t是从1970年到现在的秒数  time函数的返回值
   返回值: tm结构体,保存的是真实世界的时间。
    结构体信息如下:
    struct tm    {【重点】
   int tm_sec;			/* 秒数	[0-60] (1 leap second) */
	 int tm_min;			/* 分钟数	[0-59] */
  int tm_hour;			/* 小时	[0-23] */
	 int tm_mday;			/* 一个月中的日期		[1-31] */
  int tm_mon;			/* 月份[0-11] */
  int tm_year;			/* 年份	- 1900.  */
  int tm_wday;			/* 周中的天数(星期数).	[0-6] */
  int tm_yday;			/* 一年中的哪一天.[0-365]	*/
   }

4. Function prototype: char *asctime(const struct tm *);

     参数:  tm*   结构体指针,保存的是国际时间的结构体信息
     作用:  把国际时间转换成本地时间字符串
     返回值:时间字符串

5. Function prototype: struct tm *localtime(const time_t *); [Key points]

      参      数:  time_t 是time()函数的返回值
      作      用:  把1970年1月1号到现在的秒数转换成本地时间
      返 回  值: tm结构体指针

6. Function prototype: time_t mktime(struct tm *tm);

         参数: tm*的结构体
          返回值: time_t   在time函数中的参数中用过
         作用: 把tm结构体的时间转换成1970年1月1号到现在的秒数。

3. File attribute function

Function prototype: int stat(const char *pathname, struct stat *buf); [Key points]

  头 文 件:       #include <sys/types.h>       #include <sys/stat.h>       #include <unistd.h>
  作      用: 获取文件的属性信息
  参      数: pathname  文件路径或者文件名     buf 是结构体指针,保存的是文件属性信息
  返 回 值:  如果成功返回0  如果是失败返回-1 
 结构体解析:
      struct stat {
             dev_t     st_dev;         /* 文件使用的设备号 */
             ino_t     st_ino;         /* inode 设备的次设备号*/
             mode_t    st_mode;        /* 文件的属性(目录 设备 链接)文件对应的模式 */
            nlink_t   st_nlink;       /* 硬链接数*/
            uid_t     st_uid;         /* 拥有者的用户ID */
            gid_t     st_gid;         /* 组用户id */
            dev_t     st_rdev;        /* 设备id */
            off_t     st_size;        /* 文件的总字节数*/
            blksize_t st_blksize;     /* 磁盘块大小4k */
            blkcnt_t  st_blocks;      /*占用的磁盘数 */ 
           struct timespec st_atim;  /* 最后一次访问的时间 */
           struct timespec st_mtim;  /* 最后一次修改的时间 */
           struct timespec st_ctim;  /* 最后一次改变状态的时间 */
     }

   详解stat结构体中的 st_mode;        
   总共16位 (short类型)
   文件类型属性:(st_mode;  的前4位)
       S_ISDIR(m)  目录文件
       S_ISCHR(m)  字符设备
       S_ISBLK(m)  块设备
       S_ISFIFO(m) 管道设备
       S_ISLNK(m)  s连接设备
       S_ISSOCK(m) 网络设备

   文件权限( (st_mode;  的后9位))
       S_IRWXU     00700   拥有者有可读可写可执行权限 rwx
       S_IRUSR     00400   拥有者有可读权限 r
       S_IWUSR     00200   拥有者有可写权限 w
       S_IXUSR     00100   拥有者有可执行权限 x
       S_IRWXG      组的权限          S_IRGRP            S_IWGRP               S_IXGRP  
      S_IRWXO        (other)其他人权限    S_IROTH            S_IWOTH          S_IXOTH

3.2 To delete a file remove() calls unlink [Key Points]

      #include <unistd.h> 
      函数原型:int unlink(const char *pathname);
      返回值: 0表示成功   -1表示失败
      作用: 删除文件

3.3 Intercept file content [Key points]

   函数原型:       int truncate(const char *path, off_t length);
   头文件:#include <unistd.h>          #include <sys/types.h>
   参  数 :  path  文件路径 或者文件名
                 length  需要截取的长度
  返回值: 0表示成功   -1表示失败
 函数作用: 从path文件中文件首位置开始截取length个字节。

3.4 File permission modification

   #include <sys/stat.h>
    函数原型:       int chmod(const char *pathname, mode_t mode);
    参     数 :   pathname 文件名
                      mode是文件新的权限   0666
    作用: 修改文件权限
   返回值: 如果成功返回0 失败返回-1

3.5 Modify permission mask

     #include <sys/types.h>
     #include <sys/stat.h>
     函数原型:    mode_t umask(mode_t mask);
     参数:  mask 新的权限掩码
    返回值: 返回老的权限掩码

4. Directory operation functions

   #include <sys/stat.h>
   #include <sys/types.h>
   函数原型:int mkdir(const char *pathname, mode_t mode);  【重点】
   作用: 创建目录
   参数: pathname 文件路径 目录路径  目录名
              mode  创建权限  0777
    返回值: 成功0  失败-1

    #include <unistd.h>
   函数原型:int rmdir(const char *pathname); 【重点】
   作用:  删除目录  (空目录)
   参数: pathname  目录  
  返回值: 成功0  失败-1 
   
   #include <sys/types.h>
   #include <dirent.h>
    函数原型: DIR *opendir(const char *name); 【重点】
    作用:  打开目录  相当于cd 目录名
    参数:  name  目录名
    返回值: dir的结构体指针
   
#include <sys/types.h>
   #include <dirent.h>
   函数原型: int closedir(DIR *dirp); 【重点】
    参数:    dirp  是opendir的返回值
   作用: 关闭目录
  返回值: 成功0  失败-1 

   #include <dirent.h>
  函数原型: struct dirent *readdir(DIR *dirp); 【重点】
  参数: dirp 结构体指针
  返回值: 独到的文件或者目录信息  dirent结构体指针,失败返回NULL
 作用: 读取目录,按照文件一个一个的读取。
 返回值结构体:struct dirent {
                           ino_t          d_ino;       /* inode 数目 次设备号  inode节点 */
                           off_t          d_off;       /*现在偏移的位置*/
                           unsigned short d_reclen;    /* 目录的长度 */
                           unsigned char  d_type;      /* 文件类型  d  s  l  c  b */
                           char           d_name[256]; /* 文件名 */
       };
   struct dirent中d_type中的宏定义如下:
       DT_BLK  块设备     DT_CHR  字符设备     DT_DIR  目录         DT_REG  普通文件     DT_LNK  连接

File IO third day

1. Directory functions

#include <sys/types.h>
#include <dirent.h>
Function prototype: void rewinddir(DIR *dirp);
Function parameters: dirp This is the return value of open.
Function: reset the starting position of the directory and offset the directory. Move the setting to the starting position.

Function prototype void seekdir(DIR *dirp, long loc);
Function parameters: dirp is the return value of open
and loc is the length (offset) from the starting position of the directory to the offset position.
Function: Set the offset of the directory

函数原型: long telldir(DIR *dirp);
函数参数: open的返回值  DIR*的结构体指针。
返  回 值: 当前目录的偏移位置
作       用:   查看当前目录的偏移位置

  #include <unistd.h>
 函数原型:  int chdir(const char *path);
 函数作用:  跳转到某一个目录中
 参数 :      需要跳转的目标目录

2. Library file basics

2.1 Library file features:
       对源文件屏蔽 。
       尊重开发者的知识产权
       使用方便,方便开发。
2.2 Library file concept
      本质是上库文件是可执行的二进制文件,可以被操作系统载入内存执行
     库是别人写好,成熟的,可以重复使用的某一部分功能。
     windows和linux的库文件是不一样的,不兼容。
2.3 Library file classification
Dynamic library: (it ends with dll under windows and .so file under linux)
          1>在程序运行的时候加载到目标程序中,编译不检测。
           2> 代码小 ,程序升级简单
           3>实现资源共享
Static library: (lib file under windows, .a file under linux)
         1>在程序编译阶段连接到目标文件
          2>体积大,不利于程序的更新
          3>程序运行运行过程中不需要静态库,移植方便。
   注意:动态库和静态库是寄生虫,没办法单独运行,单独使用。

3. Static library writing

  第一步:创建一个源文件和头文件 比如说xx.c  xx.h
  第二步: 在文件中按照多文件编译写需要的函数代码。
  第三步:将库的源文件编译成目标文件 xx.o
                gcc -c x.c -o xx.o
  第四步: 将目标文件制作成静态库(lib库名.a)
              命令:ar crs lib库名.a  -o xxx.o
  第五步: 编写测试代码  有main函数的代码(调用静态库函数)
  第六步: 编译xx.c文件同时链接库文件
              gcc -o abc xxx.c -L 目录  -l 库名
   第七步:执行可执行程序
   注意: gcc -o abc xxx.c -L 目录  -l 库名中 -L后不可以有空格, -l后也不可以有空格, -l后直接加静态库名称不需要加lib的前缀和.a后缀

4. Dynamic library writing

  第一步:创建一个源文件和头文件 比如说xx.c  xx.h
  第二步: 在文件中按照多文件编译写需要的函数代码。
  第三步:将库的源文件编译成目标文件 xx.o
             命令:  gcc -fPIC  -c  xxx.c   
             fPIC 创建和地址无关的编译程序
   第四步:将.o文件编译成动态库(产生了xx.so)
             命令:gcc -shared  -fPIC -o xxxx.so  xxx.o
  第五步: 编写测试代码  有main函数的代码(调用动态库函数)
  第六步:将编译的xx.c文件编译连接动态库
           命令: gcc -o abc xxx.c -L目录  -l库名
  第七步: 运行可执行程序。
  注意: 在编译完so文件后,需要放入到/lib 或者/usr/lib下
              在gcc时 -L不可以省略 并且 -l后如果加空格则需要加动态库的后缀名 如果不加空格 则直接使用名称不用后缀。
              运行时动态库必须存在,否则没法找到函数地址,运行出错,但静态库不会,编译完成后删除不会影响代码运行。

Guess you like

Origin blog.csdn.net/qq_52531759/article/details/127181823