linux基础IO

fopen fread fwrite fseek fclose

  1 /*回顾标准库IO接口*/
  2 
  3 #include <stdio.h>
  4 #include <string.h>
  5 
  6 int main()
  7 {
  8     FILE *fp = NULL;
  9     fp = fopen("./tmp.txt", "w+");
 10     if (fp == NULL) {
 11         perror("fopen error");
 12         return -1;
 13     }
 14 
 15     char buf[1024] = "jintianrenhaoshao~~\n";
 16     //size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
 17     //返回值为 nmemb而不是size
 18     fwrite(buf, strlen(buf), 1, fp);
 19 
 20     //int fseek(FILE *stream, long offset, int whence);
 21     //对fp文件读写位置从whence开始偏移offset个字节
 22     //  whence: 
 23     //      SEEK_SET    从文件起始位置开始偏移    
 24     //      SEEK_CUR    从当前读写位置开始偏移
 25     //      SEEK_END    从文件末尾位置开始偏移
 26     //  返回值:从文件起始位置到当前跳转位置的偏移量
 27     fseek(fp, 0, SEEK_SET);
 28     //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
 29     memset(buf, 0x00, 1024);
 30     int ret = fread(buf, 1, 1023, fp);
 31     if (feof(fp)) {
 32         printf("at end of file\n");
 33     }else  {
 34         perror("fread error");
 35     }
 36     printf("ret:%d--buf:[%s]\n", ret, buf);
 37     fclose(fp);
 38     return 0;
 39 }

 文件结构体

struct FILE
{
    char *_ptr;//文件输入的下一个位置
    int _cnt;//当前缓冲区的相对位置
    char *_base;//指基础位置(文件的起始位置)
    int _flag;//文件标志
    int _file;//文件的有效性验证
    int _charbuf;//检查缓冲区状况,如果缓冲区则不读取
    int _bufsiz;//文件的大小
    char *_tmpfname;//临时文件名
};

文件描述符:

进程通过struct file_struct 结构体来描述打开的文件----------------------使用struct file*  fd_array[],文件描述符就是数组的下标

用户打开文件,操作系统通过file结构体描述文件,并将指针添加到fd_array[]中。向用户返回这个文件描述信息在数组下标中的位置,用户操作文件的时候,将下标床给操作系统,系统通过下标找到文件

进程的描述符是有上限的

文件描述符的分配原则:最小未使用原则

一个进程在运行起来默认会打开三个文件:

  • 标准输入   0(文件描述符)  stdin(文件流指针)
  • 标准输出   1(文件描述符)  stdout(文件流指针)
  • 标准错误   2(文件描述符)  stderr(文件流指针)
  1 /*系统调用接口使用*/
  2 
  3 #include <stdio.h>
  4 #include <unistd.h>
  5 #include <string.h>
  6 #include <fcntl.h>
  7 
  8 int main()
  9 {
 10     //mode_t umask(mode_t mask);
 11     //设置调用进程的文件创建权限掩码
 12     umask(0);
 13     //int open(const char *pathname, int flags, mode_t mode);
 14     //  pathname:  要打开的文件路径名
 15     //  flags: 选项参数
 16     //      必选其一:
 17     //          O_RDONLY    只读
 18     //          O_WRONLY    只写
 19     //          O_RDWR      读写
 20     //      可选项:
 21     //          O_CREAT     文件存在则打开,不存在则创建
 22     //          O_TRUNC     将文件长度截断为0(清空原有内容)
 23     //          O_APPEND    追加
 24     //  mode:   权限 0664
 25     //      (mode & ~umask)
 26     //  返回值:文件描述符(正整数)(系统调用接口的操作句柄)失败:-1
 27     int fd = open("./test.txt", O_RDWR | O_CREAT | O_APPEND | O_TRUNC, 0664);
 28     if (fd < 0) {
 29         perror("open error");
 30         return -1;
 31     }
 32     char *ptr = "jintianzhilaile 20 ren\n";
 33     //ssize_t write(int fd, const void *buf, size_t count);
 34     //  fd:     open返回的文件描述符
 35     //  buf:   要写入的数据
 36     //  count: 要写入的数据长度
 37     //  返回值:实际写入的数据长度(字节)  失败:-1
 38     int ret = write(fd, ptr, strlen(ptr));
 39     if (ret < 0) {
 40         perror("write error");
 41         return -1;
 42     }
 43 
 44     //off_t lseek(int fd, off_t offset, int whence);
 45     //  fd:     open返回的文件描述符
 46     //  offset: 偏移量
 47     //  whence:偏移起始位置
 48     //          SEEK_SET    文件起始位置
 49     //          SEEK_CUR    当前读写位置
 50     //          SEEK_END    文件末尾位置
 51     //  返回值:从文件起始位置到当前读写位置的偏移量 失败:-1
 52     lseek(fd, 0, SEEK_SET);
 53 
 54     char buf[1024] = {0};
 55     //ssize_t read(int fd, void *buf, size_t count);
 56     //  fd:     open返回的文件描述符
 57     //  buf:    内存首地址,用于存储读取的数据
 58     //  count: 要读取的数据长度
 59     //  返回值:实际读取的数据长度(字节) 失败:-1
 60     ret = read(fd, buf, 1023);
 61     if (ret < 0) {
 62         perror("read error");
 63         return -1;
 64     }
 65     printf("read buf:[%d-%s]\n", ret, buf);
 66 
 67     //int close(int fd);
 68     close(fd);
 69     return 0;
 70 }

文件流指针和文件描述符比较:

  • 库函数的操作句柄是文件流指针
  • 系统调用接口的句柄是文件描述符       

进程运行在用户态/内核态:

    用户态切换到内核态:发起系统调用  

重定向:

改变数据流向,将写入(newfd)指定文件的数据,改变写入到(oldfd)另一个文件当中

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <fcntl.h>
  4 
  5 int main()
  6 {
  7     //close(1);
  8 
  9     int fd = open("./test.txt", O_RDWR | O_CREAT);
 10     if (fd < 0) {
 11         perror("open error");
 12         return -1;
 13     }
 14     //将要打印的数据,不写入标准输出,而是写入test.txt
 15     dup2(fd, 1);
 16     //\n刷新缓冲区,仅仅针对标准输出文件才有效
 17     //其它文件,\n仅仅具备换行效果
 18     printf("fd:%d\n", fd);//stdout  ->   1 ---> test.txt
 19     //fflush(stdout);
 20 
 21     //close是系统调用接口,关闭文件时不会刷新缓冲区(因为我们所说的这个     缓冲区是stdout的缓
    冲区(用户态的缓冲区))
 22     close(fd);
 23     return 0;
 24 }

文件系统

在linux下为了更好的对文件管理,所以要对文件进行分区。每一个文件系统分区当中会将磁盘划分为数据块。

文件存储过程:通过inode_bitmap在inode区域获取空闲inode节点,通过data_bitmap获取空闲数据块,在inode节点中记录文件信息以及数据块位置,并且将文件数据写入到数据块中,将自己的目录项添加到所在目录项当中。

目录文件:文件中记录着目录下的文件信息(文件名+inode节点)-----目录项

文件读取过程:在目录项当中通过文件名获取inode节点(文件唯一),通过inode节点号在inode节点区域找到inode节点,通过inode节点中数据块地址信息,在指定数据块中读取数据。

查看文件大小:sudo dump2fs -h /dev/sda1 | grep " lnode size"

软连接/硬链接

          软链接文件:  ln  -s  srcfile   destfile          (就像文件的快捷方式,是一个独立的文件)

          硬链接文件:  ln  srcfile  destfile                 (一个文件的名字(目录项),与源文件公用一个inode节点)

          区别:

                 1.删除源文件,软链接文件将失效,硬链接无影响(链接数 -1)

                 2.软链接可以跨分区创建,硬链接不可以

                 3.软链接可以对目录创建,硬链接不可以

动态库/静态库: 生成----------------------------------二进制指令的集合

           设置LIBRARY_PATH,以便gcc能够找到编译时需要的动态链接库。

           设置LD_LIBRARY_PATH,以便程序加载运行时能够自动找到需要的动态链接库。

           gcc编译过程: 预处理 ,编译, 汇编 ,链接

                          -fPIC  产生位置无关代码        -l (指定要链接的库名称)

                          --share  指定gcc生成动态库而不是可执行程序

          动态库的生成:命名:lib(前缀)    .so(后缀)   中间是库名称

                          gcc  -fPIC -c  child.c  -o child .o

                          gcc  --share  child.o  -o  libmychild.so

          静态库的生成:命名:lib(前缀)     .a(后缀)    中间是库名称

                          gcc  -c child.c -o child .o

                          ar    -cr  libmychild.a  child.o                        -c(创建)  -r(模块替换)

动态库的使用

解决办法:

  1. 将我们生成的动态库添加到系统默认搜索库的文件中系统中    (/lib64)或者(/usr/lib/)这两个都可以。

    2.设置设置动态库运行加载的环境变量    export LD_LIBRARY_PATH=.

静态库的使用

 

注意事项:

想要使用第三方静态库,不能使用-static 选项,因为static是生成静态链接可执行程序,所有的库都是用静态库,因为标准库时动态库所以在链接时会出错,因此只需要将第三方静态库拷贝到是定路径下,使用 -L选项指定链接搜索路径,那么这个时候链接的就是静态库;

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux IO 模型是指 Linux 操作系统中的 IO 处理机制。它的目的是解决多个程序同时使用 IO 设备时的资源竞争问题,以及提供一种高效的 IO 处理方式。 Linux IO 模型主要分为三种:阻塞 IO、非阻塞 IOIO 多路复用。 阻塞 IO 指的是当程序进行 IO 操作时,会被挂起直到 IO 操作完成,这种方式简单易用,但是对于高并发环境不太适用。 非阻塞 IO 指的是程序进行 IO 操作时,如果无法立即完成,会立即返回一个错误码,程序可以通过循环不断地进行 IO 操作来实现轮询的效果。非阻塞 IO 可以提高程序的响应速度,但是会增加程序的复杂度。 IO 多路复用指的是程序可以同时监听多个 IO 设备,一旦有 IO 事件发生,就会立即执行相应的操作。IO 多路复用可以提高程序的效率,但是需要程序员手动编写代码来实现。 Linux IO 模型还有其他的实现方式,比如信号驱动 IO 和异步 IO 等。但是这些方式的使用比较复杂,一般不常用。 ### 回答2: Linux中的IO模型是指操作系统在处理输入输出的过程中所遵循的一种方式。它主要包括阻塞IO、非阻塞IO、多路复用IO和异步IO四种模型。 阻塞IO是最简单的IO模型,当一个IO操作发生时,应用程序会被阻塞,直到IO操作完成才能继续执行。这种模型的特点是简单直接,但是当有多个IO操作时会造成线程的阻塞,影响系统的性能。 非阻塞IO是在阻塞IO基础上发展而来的,应用程序在发起一个IO操作后可以继续执行其他任务,不必等待IO操作的完成。但是需要通过轮询来不断地检查IO操作是否完成,效率相对较低。 多路复用IO使用select、poll、epoll等系统调用来监听多个IO事件,当某个IO事件就绪时,应用程序才会进行读写操作,避免了前两种模型的效率问题。多路复用IO模型适用于连接数较多时的场景,如服务器的网络通信。 异步IO是最高效的IO模型,应用程序发起一个IO操作后,立即可以执行其他任务,不需要等待IO操作的完成。当IO操作完成后,操作系统会通知应用程序进行后续处理。异步IO模型常用于高吞吐量、低延迟的应用,如高性能服务器和数据库等。 总之,Linux IO模型提供了多种不同的方式来处理输入输出,每种模型都有其适用的场景和特点。选择合适的IO模型可以提高系统的性能和效率。 ### 回答3: Linux IO模型是指操作系统中用于处理输入输出操作的一种方法或机制。在Linux中,常见的IO模型有阻塞IO、非阻塞IOIO多路复用和异步IO。 阻塞IO是最基本的IO模型,当应用程序发起一个IO请求时,它将一直阻塞等待直到IO操作完成,期间无法做其他任务。虽然简单易用,但是对资源的利用不高。 非阻塞IO在发起一个IO请求后,不会阻塞等待IO操作完成,而是立即返回并继续做其他任务。应用程序需要不断地轮询IO操作状态,直到操作完成。由于需要不断轮询,对CPU的占用较高,但可以提高资源的利用率。 IO多路复用是通过一个线程同时监听多个IO事件,从而实现并发处理多个IO操作。在IO多路复用模型中,应用程序不需要进行轮询,而是通过调用select、poll或epoll等系统调用监听多个文件描述符的IO事件。这样可以在单个线程中处理多个IO操作,提高并发性能。 异步IO模型在发起一个IO请求后,应用程序不需要等待IO操作完成,而是继续做其他任务。当IO操作完成后,操作系统会通知应用程序。异步IO模型需要操作系统的支持,效率较高,但实现较为复杂。 通过选择合适的IO模型,可以根据不同的应用场景来提高IO操作的效率和性能。例如,对于需要同时处理大量连接的服务器应用,IO多路复用是一种常见的选择;而对于需要处理大量IO操作的高性能服务器,则可以考虑使用异步IO模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值