操作系统与网络 (6. 基础IO)

站在山顶和站在山脚下的两个人,虽然地位不同,但在对方眼里,同样的渺小!

6. 基础IO

6.1 标准库IO接口
6.1.1 fopen (r/r+/w/w+/a/a+///FILE *fopen(const char *path, const char *mode);

1. 参数解析

  • path: 文件路径名
  • mode:
    r 只读打开已经存在的文件
    r+ 读者打开已经存在的文件
    w 只写打开文件,若文件不存在则创建,存在则长度截为0
    w+ 读写打开文件,若文件不存在则创建,创建的文件权限默认为664;
    若文件存在则长度截为0
    a 追加写打开,若文件不存在则创建,每次总是写到文件末尾
    a+ 读写(追加),文件读写位置刚打开的时候在起始位置,当写入的时候文件读写位置移动到文件末尾;若文件不存在,则创建文件。

2. 返回值

  • 文件的操作句柄----文件流指针
6.1.2 size_t fwrite(void *ptr, size_t size, size_t nmemb,FILE *stream);

1. 参数解析

  • ptr:要写入的数据
  • size:要写入的块大小 —fwrite对数据进行按块操作
  • nmemb:要写入的块个数
  • stream:fopen返回的文件流指针

2. 返回值

  • 实际写入的块个数
6.1.3 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

1. 参数解析

  • ptr: 用于接收数据的缓冲区
  • size:要读取的块大小
  • nmemb:要读取的块个数
  • stream:文件流指针

2. 返回值

  • 实际读取到的块个数 文件末尾:0
6.1.4 int fseek(FILE *stream, long offset, int whence);

1. 参数解析

  • whence:跳转的起始位置
  • SEEK_SET 文件起始位置
  • SEEK_CUR 当前读写位置
  • SEEK_END 文件末尾位置
  • offset: 偏移量
    2. 返回值
  • int型
6.1.4 int fclose(FILE *fp);

review.c

/*===============================================================
 * Copyright (C) . All rights reserved.")"
 * 文件名称:
 * 创 建 者: yangjie
 * 创建日期: 2020-1-6
 * 描    述:FILE *fopen(const char *path, const char *mode);
 *          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);
 *          int fseek(FILE *stream, long offset, int whence);
 *          int fclose(FILE *stream);
 * =============================================================*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  // FILE *fopen(const char *path, const char *mode);
  // path: 文件路径名
  // mode: 
  // r  只读打开                            r+ 可读可写
  // w  只写,文件不存在则创建, 若文件存在则清空原有内容
  // w+ 相较于w, 多了可读操作
  // a  追加写打开, 若文件不存在则创建, 每次总是写到文件末尾
  // a+ 相较于a, 多出了可读操作
  // 返回值: 文件的操作句柄----文件流指针
  FILE* fp = fopen("tmp.txt", "w+");
  if(fp == NULL)
  {
    perror("fopen errror!");
    return -1;
  }
  // size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
  // ptr:   要写入的元素
  // size:  要写入的块大小,--fwrite对数据进行按块操作
  // nmemb: 要写入的块个数
  // stream: fopen返回的文件流指针
  // fseek(fp,10,SEEK_END);
  char* ptr = "evething would be better!!!\n";
  size_t ret = fwrite(ptr,strlen(ptr),1,fp);                     // size_t 无符号的32位整数
  if(ret == 0)
  {
    perror("fwite errror!");
    return -1;
  }

  // int fseek(FILE *stream, long offset, int whence);
  // 对stream文件的读写位置跳转到whence位置偏移offset个字节处
  // whence: 跳转的起始位置
  // SEEK_SET   文件起始位置
  // SEEK_CUR   当前读写位置
  // SEEK_END   文件末尾位置
  // offset: 偏移量
  fseek(fp,0,SEEK_SET);

  // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  // ptr: 用于接收数据的缓冲区
  // size: 要读取的块大小
  // nmemb: 要读取的块个数
  // stream: 文件流指针
  // 返回值: 实际返回的块个数
  char buf[1024] = {0};
  ret = fread(buf,1023,1,fp);
  perror("fread error!");
  printf("ret: %d-[%s]\n",ret,&buf[2]);

  // int fclose(FILE *stream);
  fclose(fp);
  return 0;
}

运行结果

[dev@localhost baseio]$ ./review
fread error!: Success
ret: 0-[ething would be better!!!
]
[dev@localhost baseio]$
6.1.5 printf,sprintf, fprintf
  1. printf(格式化字符串,输出到终端)
  2. sprintf(格式化字符串,将格式化后的字符串写入到一个buff中)
  3. fprinf(格式化字符串,将格式化后的子串写入到文件中)
6.1.6 fgets
6.1.7 fputs
6.2 系统调用接口
6.2.1 int open(const char *pathname, int flags, mode_t mode);

1. 参数解析

  • pathname: 要打开或创建的目标文件
  • flags: 标志选项
  • 参数:
    必须选项(这三个常量,必须指定一个且只能指定一个)
    O_RDONLY: 只读打开
    O_WRONLY: 只写打开
    O_RDWR : 读,写打开
    非必须选项
    O_CREAT: 若文件存在则打开,不存在则创建;
    O_APPEND: 追加写;
    O_TRUNC:若文件存在则将文件长度截为0;
    O_EXCEL:与O_CREAT同时使用,若文件存在则报错。
  • mode:若文件不存在,需要创建的时候,用于指定创建文件权限
    2. 返回值
  • 成功:新打开的文件描述符
  • 失败:返回-1
6.2.2 ssize_t read(int fd, void *buf, size_t count);

1. 参数解析

  • fd:open打开文件所返回的文件描述符
  • count:要写入的字节数
  • buff:要写入的数据

2. 返回值

  • 成功:实际写入的字节数
  • 失败:返回-1
6.2.3 ssize_t write(int fd, const void *buf, size_t count);

1. 参数解析

  • fd:open打开文件所返回的文件描述符
  • count:要写入的字节数
  • buff:要写入的数据

2. 返回值

  • 成功:实际写入的字节数
  • 失败:返回-1
6.2.4 off_t lseek(int fd, off_t offset, int whence);

1. 参数解析

  • 跳转fd文件的读写位置到指定处
    whence:SEEK_SET SEEK_CUR SEEK_END
  • offset:偏移量
    2. 返回值
  • 成功:实际写入的字节数
  • 失败:返回-1
6.2.5 int close(int fd);

systemio.c

/*===============================================================
 * Copyright (C) . All rights reserved.")"
 * 文件名称:systemio
 * 创 建 者: yangjie
 * 创建日期: 2020-1-6
 * 描    述: 这个demo用于演示系统调用io接口的基本使用
 *           int open(const char *pathname, int flags, mode_t mode);
 *           ssize_t read(int fd, void *buf, size_t count);
 *           ssize_t write(int fd, const void *buf, size_t count);
 *           off_t lseek(int fd, off_t offset, int whence);
 *           int close(int fd);
 *           mode_t umask(mode_t mask);
 * =============================================================*/

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
    // mode_t umask(mode_t mask);
    // 将当前进程的文件创建权限掩码修改为mask
    umask(0);
    // int open(const char *pathname, int flags, mode_t mode);
    int fd  = open("test.txt",O_RDWR|O_CREAT|O_APPEND,0664);
    if(fd < 0 )
    {
      perror("open error!");
      return -1;
    }
    // ssize_t read(int fd, void *buf, size_t count);
    // fd: open打开文件所返回的文件描述符
    // buf: 要写入的数据
    // count: 要写入的字节数
    // 返回值: 实际写入的字节数
    char* data = "life is the sun!!!\n";
    ssize_t ret = write(fd, data, strlen(data));
    if(ret < 0)
    {
      perror("write error!");
      return -1;
    }
    // off_t lseek(int fd, off_t offset, int whence);
    // 跳转fd文件的读写位置到指定处
    // whence: SEEK_SET  SEEL_CUR  SEELK_END
    // offset: 偏移量
    lseek(fd,0,SEEK_SET);

    // ssize_t read(int fd, void *buf, size_t count);
    // 从fd文件中读取count长度的数据, 放到buf中
    // 返回值: 返回实际读取到的字节数    失败: 返回-1
    char buf[1024] = {0};
    ret = read(fd, buf, 1023);
    if(ret < 0)
    {
      perror("read error!");
      return -1;
    }
    printf("ret: %d-[%s]\n",ret,&buf);

    // int close(int fd);
    close(fd);
}

运行结果

[dev@localhost baseio]$ ./systemio
ret: 39-[fd:1
Mind and Hand!
life is the sun!!!
]
[dev@localhost baseio]$
6.3 文件描述符
6.3.1 概念

文件描述符:系统调用IO接口的操作句柄int,实际上是一个数字。
文件流指针:标准IO接口的操作句柄 FILE*。

6.3.2 文件描述符与文件流指针的关系
  • 文件流指针中封装了文件描述符,文件流指针结构体中包含了一个成员就是我们的文件描述符,文件流指针中还定义了一个缓冲区,我们所说的换行刷新缓冲区,实际上就是刷新的这个缓冲区,这个缓冲区用于将短小数据合成大数据一次性写入文件,这样可以提高效率,系统调用接口没有这个缓冲区。
6.3.3 LInux下3个缺省打开的文件描述符

标准输入:0
标准输出:1
标准错误:2

  • 对应的物理设备一般是:键盘、显示器、显示器
6.3.4 文件描述符的分配原则

(1)在 files_struct 数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符;
(2)最小未使用原则;
(3)分配有限。

6.4 重定向
6.4.1 概念
  • 重定向指的是文件描述符的重定向,文件描述符这个下标中的文件描述信息,从一个文件变成另外一个文件,这时候用户通过文件描述符项文件写入数据的时候,文件描述符并没有改变依然还是相同的数字,但是因为描述符下标中的文件描述信息的改变,而导致数据流向另外一个文件。
6.4.2 功能
  • 改变数据的流向。
6.4.3 重定向的分类
>>追加重定向
O_APPEND(向原有内容下方添加新内容)
>清空重定向
O_TRUNC(清空原有内容分后添加新内容)
<标准输入重定向

filedesc.c

/*=============================================================== 
*   Copyright (C) . All rights reserved.")
*   文件名称: 
*   创 建 者:yangjie
*   描    述:体会文件描述符分配规则
================================================================*/

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
    close(1);
    int fd = open("./test.txt", O_CREAT|O_RDWR, 0664);
    if(fd < 0) {
        perror("open error");
        return -1;
    }

    printf("fd:%d\n", fd);
    fflush(stdout);

    close(fd);
    return 0;
}

运行结果

[dev@localhost baseio]$ ./filedesc
[dev@localhost baseio]$ cat test.txt 
fd:1
Mind and Hand!

cat test.txt
cat tmp.txt

[dev@localhost baseio]$ cat test.txt 
fd:1
Mind and Hand!
life is the sun!!!
[dev@localhost baseio]$ cat tmp.txt 
evething would be better!!!
6.4.4 使用dup2系统调用

(1)接口说明

  • int dup2(int oldfd, int newfd);
    (2)功能
  • 文件复制。
6.5 文件系统
6.5.1 说明
  • Linux下的文件系统以 ext3/4 为主,主要是组织硬盘如何存储一个文件。
6.5.2 磁盘文件系统的组成
  • (1)数据块(存储数据的区域)
  • (2)iNode节点区域(存储文件的描述信息,如文件大小,所有者,最近修改时间等)
  • (3)iNode bitmap (inode 节点分配剩余情况,每个bit表示一个inode是否空闲可用)
  • (4)Block bitmap (数据块剩余情况)
  • (5)超级块(文件系统的记录信息)
  • (6)Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成,政府管理各区的例子;
  • (7)GDT,Group Descriptor Table:块组描述符,描述块组属性信息。
6.5.3 软链接/硬链接

(1)软链接

  • 独立的文件,功能类似于windows下的快捷方式
  • ln -s 文件名(生成软链接文件)

(2)硬链接

  • 一个文件的目录项/别名
  • ln 文件名(生成硬链接文件)

(3)软链接与硬链接的区别

  1. 软连接文件是一个单独的文件,数据中存储源文件路径;硬链接文件是一个文件别名(目录项),与源文件操作同一个inode节点;
  2. 软连接可以对目录创建,硬链接则不可以;
  3. 软连接可以跨区建立,硬链接则不可以;
  4. 删除源文件,软连接文件失效,硬链接文件无影响(链接数-1)。
6.5.4 文件的存储流程
  • (1)通过 databitmap 快速找到空闲的数据块,存储数据;
  • (2)并且通过 inode bitmap 快速找到一个空间的 inode节点,保存文件的源信息(名称、大小、权限、数据的存储位置…);
  • (3)将文件的(inode节点号+文件名)目录项保存到所在目录文件中;
6.5.5 文件的查找流程
  • (1)通过目录项(文件名称+文件对应的 inode节点号)快速找到文件的 inode节点号;
  • (2)通过 inode节点号可以在inode table 中快速的找到文件的 inode 节点;
  • (3)通过 inode节点可以找到文件数据存储位置,进而获取到数据 inode节点(文件的描述信息,其中有文件数据的存储位置);
6.6 库的生成
6.6.1 动态库

(1)定义

  • 程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

(2)动态库的生成
gcc -fPIC -c main.c -o main.o
fPIC(生成目标代码时产生位置无关代码)
gcc --share main.o -o libmain
–share(要生成的是动态库而不是可执行程序)

(3)库文件

  • 库文件实际上就是封装了一大堆已经编译完成的代码文件,通过链接这个库进而获取到响应函数而实现。

(4)动态库命名
lib是前缀
.so是后缀
中间是库名称

6.6.2 静态库

(1)定义

  • 程序在编译链接的时候把库的代码链接到可执行文件中。

(2)动态库的生成
gcc -c main.c -o main .o
ar -cr lib main.a main.o

(3)静态库生成的链接器
-c(创建静态库)
-f(模块替换)

(4)静态库的命名

  1. lib是前缀
  2. .so是后缀
  3. 中间是库名称
6.7 库的使用
6.7.1 动态库的使用

将库文件放到指定的路径下
/lib/lib64/ usr/lib…
设置环境变量
LIBRARY_PATH
l
链接动态库,只要库名即可(去掉lib以及版本号)
L
链接库所在的路径.
示例: gcc main.o -o main –L. -lhello

6.7.2 运行动态库

前提: 动态库使用
将库文件放到指定的路径下
/lib/lib64/ usr/lib…
设置环境变量
LIBRARY_PATH
ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值