linux

cp命令实现

 

 lseek

 

 标准io&&追代码

 

 缓冲区

 

 open

 

 

 

 

 

 

 

 

一 文件IO
1.1 什么是文件IO
    所谓文件IO指的就是操作系统提供支持的API接口,以对文件的输入和输出
1.2 操作系统的分层
    应用层
        应用APP,bash脚本等
    -----------------------------------
    内核层
        接收应用层发来的通知,去操作相应的硬件 (操作系统)
        文件IO的接口都来自于内核层
    -----------------------------------
    硬件层
        硬盘,鼠标,键盘,lcd,摄像头等
1.3 学习IO的前提
    1> linux下一切皆文件
    2> 文件IO是由操作系统提供的API接口,不同操作系统之间不通用
    3> 由于文件IO直接由内核提供,所以效率比较高,但是频繁的调用
       会极大的浪费CPU资源
    4> linux  :open write read
       windows:_open _write _read
       ios    : Open Write Read
    5> 文件描述符:是一个文件的代表,系统内部为结构体指针数组的下标
    6> 文件描述符中:前三个已经被系统占用
            0:标准输入 (从终端文件写入内存)
            1:标准输出 (从内存输出到终端文件)
            2:标准错误输出(从内存直接输出到终端)
    7> errno:错误码(系统返回的错误码,其对应着一些错误原因)
             错误原因可以使用perror函数进行打印
    8> 文件掩码:umask(控制文件创建的权限)
1.4 文件IO的五大函数(linux)
    1> 打开文件         (open)
    2> 写入文件         (write)
    3> 读取文件         (read)
    4> 操作文件读写指针 (lseek)
    5> 关闭文件         (close)
1.5 man手册
    下表显示了手册的 章节 号及其包含的手册页类型。
       1 可执行程序或 shell 命令
       2 系统调用(内核提供的函数)
       3 库调用(程序库中的函数)
       4 特殊文件(通常位于 /dev)
       5 文件格式和规范,如 /etc/passwd
       6 游戏
       7 杂项(包括宏包和规范,如 man(7),groff(7))
       8 系统管理命令(通常只针对 root 用户)
       9 内核例程 [非标准]
    使用方法:man 章节数 查找目标
1.6 文件IO的操作
【1】open
头文件:#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, mode_t mode);
功能: 打开一个文件
参数:
    pathname:打开文件的路径+名称
    flags   :打开文件的方式(方式之间用|隔开)
    以下必须三选一:
         O_RDONLY: 以只读的方式打开文件 
         O_WRONLY: 以只写的方式打开文件
         O_RDWR  : 以读写的方式打开文件
    可选项:
         O_CREAT : 如果文件存在则直接打开,如果文件不存在则创建之
                   (如果加上O_CREAT,则必须加上第三个参数 mode)
         O_APPEND: 以追加写的方式
         O_TRUNC : 以清空的方式写入
         O_NONBLOCK or O_NDELAY:以非阻塞的方式打开一个文件
    mode    :创建文件的权限(三位八进制数组成)
返回值:
    成功:返回文件描述符
    失败:返回-1
【2】read
原型:#include <unistd.h>
头文件:ssize_t read(int fd, void *buf, size_t count);
功能:从文件中获取一段内容写入到内存buf中
参数:
    fd:目标文件描述符(从哪个文件中读)
    buf:从文件中读取后写入内存的位置
    count:写入文件的字节个数(写入内存的最大字节个数)
返回值:
        成功:返回   读取到的字节个数
              返回0:读到文件的末尾
        失败:返回 -1
【3】write
头文件:#include <unistd.h>    
原型:ssize_t write(int fd, const void *buf, size_t count);
功能:向文件中写入一段字符串
参数:
    fd:目标文件描述符(向哪个文件写入内容)
    buf:写入字符串的首地址
    count:写入文件的字节的个数
    注意:如果buf的长度小于count的值,则会产生空洞文件
          如果buf的长度大于count的值,则写入count大小的字节
返回值:
    成功:返回   实际写入文件的字节的个数
          返回0:向文件中写入0个字节
    失败:返回-1
    
作业:实现cp命令(cp 源文件路径 目标文件路径)
要求:可以支持拷贝图片(二进制文件)
提示:
    1.源文件路径 目标文件路径 使用命令行参数实现
    2.open函数打开两个文件(源文件,目标文件)
    3.循环从源文件中读取内容,再循环写入新的文件中
【4】lseek
头文件:#include <sys/types.h>
       #include <unistd.h>
原型:off_t lseek(int fd, off_t offset, int whence);
功能:操作文件读写指针的偏移
参数:
        fd:目标文件描述符
        offset:偏移基准
          SEEK_SET
                 以文件开头为基准进行指针的偏移
          SEEK_CUR
                 以当前读写指针的位置为基准进行偏移
          SEEK_END
                 以文件末尾为基准进行读写指针的偏移
        whence:偏移量
                    如果偏移量为负数,表示往前偏移whence个字节
                    如果偏移量为正数,表示往后偏移whence个字节
返回值:
    成功:返回文件读写指针距离文件开头的偏移量
    失败:返回 -1。
【5】close
头文件:#include <unistd.h>
原型:int close(int fd);
功能:关闭一个文件
参数:
    fd:目标文件描述符
返回值:
    成功:返回 0
    失败:返回 -1

二 标准IO
2.1 什么是标准IO
    所谓标准IO,就是在文件IO的基础上封装出来的一系列接口
    主要目的就是为了其可移植性和减少内核的调用。
2.2 搜索引擎(追代码工具 ctag)
    1> 找到搜索的路径
    2> vi -t FILE
    3> 输入对应的数字
    4> ctrl + ] 进入下一级路径
    5> ctrl + t 回到上一级路径
    
2.3 文件流指针(FILE*)
     所谓文件流指针,就是在文件描述符的基础上,封装出来的一个
     结构体指针,文件流指针就是标准IO中操作文件的指针
        标准输入流指针:stdin
        标准输出流指针:stdout
        标准错误输出流指针:stderr
    文件流指针结构体:
           241    struct _IO_FILE {
           242      int _flags;        /* High-order word is _IO_MAGIC; rest is flags. */
           243    #define _IO_file_flags _flags
           244    
           245      /* The following pointers correspond to the C++ streambuf protocol. */
           246      /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
           247      char* _IO_read_ptr;    /* Current read pointer */
           248      char* _IO_read_end;    /* End of get area. */
           249      char* _IO_read_base;    /* Start of putback+get area. */
           250      char* _IO_write_base;    /* Start of put area. */
           251      char* _IO_write_ptr;    /* Current put pointer. */
           252      char* _IO_write_end;    /* End of put area. */
           253      char* _IO_buf_base;    /* Start of reserve area. */
           254      char* _IO_buf_end;    /* End of reserve area. */
           255      /* The following fields are used to support backing up and undo. */
           256      char *_IO_save_base; /* Pointer to start of non-current get area. */
           257      char *_IO_backup_base;  /* Pointer to first valid character of backup area */
           258      char *_IO_save_end; /* Pointer to end of non-current get area. */
           259    
           260      struct _IO_marker *_markers;
           261    
           262      struct _IO_FILE *_chain;
           263    
           264      int _fileno;   //文件描述符
           265    #if 0
           266      int _blksize;
           267    #else
           268      int _flags2;
           269    #endif
           270      _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
           271    
           272    #define __HAVE_COLUMN /* temporary */
           273      /* 1+column number of pbase(); 0 is unknown. */
           274      unsigned short _cur_column;
           275      signed char _vtable_offset;
           276      char _shortbuf[1];
           277    
           278      /*  char* _save_gptr;  char* _save_egptr; */
           279    
           280      _IO_lock_t *_lock;
           281    #ifdef _IO_USE_OLD_IO_FILE
           282    };

        
2.4 缓冲区分类
    1> 行缓冲(标准输入(文件描述符:0)和标准输出(文件描述符:1))
        (1)行缓冲的大小--->1024个字节
        (2)刷新缓冲区的条件
                <1> 遇到\n会刷新缓冲区
                <2> 程序结束会刷新缓冲区
                <3> 缓冲区满会刷新缓冲区
                <4> 当标准输入和标准输出有一方需要使用缓冲区时
                    另一方需要让出缓冲区
                <5> 程序员手动刷新缓冲区(fflush)
    2> 全缓冲(除行缓冲和无缓冲外)
        (1) 全缓冲的大小--->4096个字节
        (2) 全缓冲刷新的条件
                <1> 程序结束会刷新缓冲区
                <2> 缓冲区满会刷新缓冲区
                <3> 程序员手动刷新缓冲区(fflush)
    3> 无缓冲(标准错误输出(文件描述符:2))

2.5 相关API接口
【1】fopen
头文件:#include <stdio.h>
原型:FILE *fopen(const char *path, const char *mode);
功能:打开一个文件
参数:
    path:打开文件的路径
    mode:
      ┌─────────────┬───────────────────────────────┐
      │fopen() mode            │ open() flags                  │
      ├─────────────┼───────────────────────────────┤
      │     r                            │ O_RDONLY                      │
      ├─────────────┼───────────────────────────────┤
      │     w                           │ O_WRONLY | O_CREAT | O_TRUNC  │
      ├─────────────┼───────────────────────────────┤
      │     a                           │ O_WRONLY | O_CREAT | O_APPEND │
      ├─────────────┼───────────────────────────────┤
      │     r+                         │ O_RDWR                        │
      ├─────────────┼───────────────────────────────┤
      │     w+                        │ O_RDWR | O_CREAT | O_TRUNC    │
      ├─────────────┼───────────────────────────────┤
      │     a+                         │ O_RDWR | O_CREAT | O_APPEND   │
      └─────────────┴───────────────────────────────┘
返回值:
    成功:返回一个文件流指针
    失败:返回NULL
【2】fgetc
头文件:#include <stdio.h>
原型:int fgetc(FILE *stream);
功能:从文件中获取一个字符
参数:
    stream:目标文件流指针
返回值:
    成功:返回获取到的字符
          读取到文件末尾,返回EOF
    失败:EOF
【3】feof
头文件:#include <stdio.h>
原型:int feof(FILE *stream);
功能:检测文件是否已经到达末尾
参数:
    stream:目标文件流指针
返回值:到达文件末尾:返回非0
        未到达:      返回0
【3】fputc
头文件:#include <stdio.h>
原型:int fputc(int c, FILE *stream);
功能:向一个文件输出一个字符
参数:
        c:想要写入文件的字符
        stream:目标文件流指针
返回值:
        成功:返回成功写入的字符的ascii
        失败:返回EOF

练习:使用 fgetc和fputc实现cp命令。

【4】fgets(行读取)
头文件:#include <stdio.h>
原型:char *fgets(char *s, int size, FILE *stream);
功能:从指定的文件中获取一行字符串
参数:
    s:从文件中获取内容后写入的位置
    size:一次获取字符串的长度(最多读取一行,并且将\n也写入内存)
    stream:目标文件流指针
返回值:
    成功:返回读取到的字符串
          读取到文件末尾:返回NULL
    失败:返回NULL
【5】fputs        
头文件:#include <stdio.h>
原型:int fputs(const char *s, FILE *stream);
功能:向指定的文件输出一个字符
参数:
    s:想要向文件中写入的字符串
    stream:目标文件流指针
返回值:
    成功:返回一个非负数
    失败:返回EOF
作业:1.通过以上函数计算文件的行数
      2.通过以上函数计算文件的大小
      3.员工管理系统,要求运行后,可以获取之前插入的数据(周一验收)

【6】fread(二进制读取)
头文件:#include <stdio.h>
原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从指定的文件中读取 size *nmemb个字节大小的数据到内存ptr中
参数:
    ptr :保存从文件中读取到内容的首地址
    size: 读取文件的大小 
    nmemb:读取内容的个数
    stream:目标文件流指针
返回值:
    成功:返回读取到的项目(以size大小为单位)的个数
          读到文件末尾:返回0
    失败:返回0
【7】fwrite
头文件:#include <stdio.h>
原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb,
                     FILE *stream);
功能:向指定的文件中写入size *nmemb个字节
参数:
    ptr:内存的首地址
    size:一个数据包的大小
    nmemb:数据包的个数
    stream:目标文件流指针
返回值:
    返回成功写入文件中数据包的个数
    失败:返回0
【8】fseek
头文件:#include <stdio.h>
原型:int fseek(FILE *stream, long offset, int whence);
功能:操作读写指针的偏移
参数:
    stream:目标文件流指针
    offset: 偏移的基准位置
        SEEK_SET:以文件开头为基准进行偏移
        SEEK_CUR:以文件当前位置为基准进行偏移
        SEEK_END:以文件末尾为基准进行偏移
    whence:偏移量
            注意:负数表示向前偏移
返回值:              正数表示向后偏移
    成功:返回0
    注意:(使用ftell()函数获取偏移量.)
    失败:返回-1
【9】sprintf
头文件:#include <stdio.h>
原型:int sprintf(char *str, const char *format, ...);
功能:向某一块内存按照格式输入字符串
参数:
    str   :字符串输入内存的首地址
    format:格式化字符串
    ...   : 可变参数
返回值:    成功输出的字符的个数          
    
【10】fprintf
头文件:#include <stdio.h>
原型:int fprintf(FILE *stream, const char *format, ...);
功能:向固定的文件按照格式写入字符串
参数:
    stream:目标文件流指针
    format:格式化字符串
    ...   : 可变参数
返回值:    成功写入文件的字符的个数    

三 总结
1.标准IO和文件IO的区别?
    标准IO是在文件IO的基础上,增加了缓冲区,封装出来的一系列接口
    可移植性:标准IO的移植性更好
    使用区别:当我们需要频繁的调用IO接口,但是又不着急立刻
    读写文件内容,这个时候,选择标准IO
              当需要高效的读取文件内容,且仅用于特定的环境,但是又不频繁调用
              选择文件IO
 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值