【Linux学习】基础IO1

简介: 【Linux学习】基础IO

前言

该文章基于Linux环境用于介绍基础IO。本文涉及C语言文件IO相关操作、认识文件相关的系统调用接口、认识文件操作符,理解重定向、通过对比fd和FILE,理解系统调用与库函数之间的关系、理解文件系统中的inode相关概念、认识软硬连接以及认识动静态库,结合gcc制作动静态库等。


一、C语言文件IO

1. C语言文件接口以及打开方式

  1. 文件接口
文件操作函数 功能说明
fopen 打开文件
fclose 关闭文件
fwrite 以二进制形式写入文件
fread 以二进制形式读取文件
fputc 写入一个字符
fgetc 读取一个字符
fputs 写入一个字符串
fgets 读取一个字符串
fprintf 格式化写入数据
fscanf 格式化读取数据
fseek 设置文件指针的位置
ftell 计算当前文件指针相对于起始位置的偏移量
rewind 设置文件指针到文件的起始位置
ferror 判断文件操作过程中是否发生错误
feof 判断文件指针是否读取到文件末尾
  1. 打开方式
打开方式 说明
r 打开文件用于只读
r+ 打开文件用于读和写
w 打开文件用于写文件,若文件存在,则会清空文件内容,若文件不存在,则会创建之
w+ 与 “w” 的区别在于,增加了读
rb 打开文件,用二进制形式读
rb+ 与"rb" 的区别在于,增加了写
wb 打开文件,以二进制形式写
wb+ 与"wb" 的区别在于,增加了读
a 以尾部追加的方式打开一个文本文件用于只写
a+ 与"a" 的区别在于,增加了读
ab 以尾部追加的方式打开一个二进制文件用于只写
ab+ 与"a" 的区别在于,增加了读

下面是用C语言进行读写操作的例子:

  • 写文件
#include <stdio.h>
#include <string.h>
int main()
{
  FILE* fp = fopen("myfile.txt", "w");
  if (!fp) {
    printf("fopen error!\n");
  }
  const char* msg = "hello world!\n";
  int count = 5;
  while (count--) {
    fwrite(msg, strlen(msg), 1, fp);
  }
  fclose(fp);
  return 0;
}


结果:

  • 读文件
#include <stdio.h>
#include <string.h>
int main()
{
  FILE* fp = fopen("myfile.txt", "r");
  if (!fp)
  {
    printf("fopen error!\n");
  }
  char buf[1024];
  const char* msg = "hello world!\n";
  while (1)
  {
    //注意返回值和参数,此处有坑,仔细查看man手册关于该函数的说明
    size_t s = fread(buf, 1, strlen(msg), fp);
    if (s > 0) {
      buf[s] = 0;
      printf("%s", buf);
    }
    if (feof(fp)) {
      break;
    }
  }
  fclose(fp);
  return 0;
}


结果:

2. 对当前路径的理解


学习了C语言文件操作过后,我们知道当用fopen以写入的方式打开一个文件时,如果该文件不存在,则会在当前路径下创建该文件,那么什么是当前路径呢?

例如,我们在test_file目录下运行mytest,发现该目录出现了一个myfile.txt文件。

那么,是否可以下结论说,当前路径就是我的可执行程序所在的路径呢?现在我们将myfile.txt删除,回退到上一级目录下再次执行mytest。

我们可以发现,myfile.txt最终出现在了当前所执行mytest的路径中。

当该可执行程序执行起来变成进程之后,我们可以通过获取该进程的PID,然后根据PID在根目录下的proc目录查看该进程的信息。

在这里我们可以看到两个软链接文件cwd和exe,cwd就是进程运行时我们所处的路径,而exe就是该可执行程序的所处路径。

由此我们可以得出结论:我们这里所说的当前路径不是指可执行程序所处的路径,而是指该可执行程序运行成为进程时我们所处的路径

3. 默认打开的三个流

Linux下一切皆文件,意思是在Linux中我们可以把任何东西都看成文件,那么显示器和键盘等也就相当于是文件。因为我们能在显示器中看到数据,是因为我们向显示器里面写入了数据,电脑能够得到我们从键盘敲入的字符,是因为电脑从键盘中读取了数据。


那么既然显示器和键盘等都是文件,为什么我们不需要提前打开"显示器文件" 和 “键盘文件”,就能直接进行键盘和显示器的相关操作呢?


需要注意的是,打开文件一定是进程运行的时候打开的,而任何进程在运行的时候都会默认打开三个输入输出流,即标准输入流、标准输出流以及标准错误流,对应到C语言当中就是stdin、stdout以及stderr。


其中,stdin对应的是键盘,stdout和stderr对应的是显示器。

通过查看man手册,我们会发现stdin、stdout以及stderr都是FILE* 类型的,也就是文件类型。

extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;

当我们的C程序被运行起来时,操作系统就会默认使用C语言的相关接口将这三个输入输出流打开,之后我们才能调用类似于scanf和printf之类的函数向键盘和显示器进行相应的输入输出操作。


值得注意的是: 不止是C语言当中有标准输入流、标准输出流和标准错误流,C++当中也有对应的cin、cout和cerr,其他所有语言当中都有类似的概念。实际上这种特性并不是某种语言所特有的,而是由操作系统所支持的。

二、 系统文件IO

1. 系统接口

open

系统接口中使用open函数打开或者创建目标文件,man手册中的open:

参数解读:

pathname:要打开或创建的目标文件

flags: 打开文件时,传入的参数选项,用一个或者多个常量进行 “或” 运算,构成flags。

mode:给目标文件设置的权限

flags参数:

常量名 说明
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读,写打开
O_CREAT 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND 追加写

注意:前面三个常量,必须指定一个且只能指定一个。

返回值:

打开成功返回目标文件的文件描述符fd,失败则返回 -1。

write

系统接口中使用write向目标文件写入数据,man手册中的write:

参数解读:


fildes:文件描述符

buf:数据缓冲区

nbyte:向文件中写入数据的字节数

返回值:

ssize_t:有符号整型,在32位机器上等同于int,在64位机器上等同于long

写入成功,则返回实际写入数据的字节数;

写入失败,则返回 -1。

利用系统接口写文件的例子:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
    umask(0);
    int fd = open("myfile.txt", O_WRONLY | O_CREAT, 0664);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    int count = 5;
    const char* msg = "hello world !\n";
    int len = strlen(msg);
    while(count--)
    {
        write(fd, msg, len);
    }
    close(fd);
    return 0;
}

read

系统接口中使用read函数读取文件中的数据,man手册中的read:


参数解读:

fildes:文件描述符

buf:数据缓冲区

nbyte:向文件中写入数据的字节数

返回值:

ssize_t:有符号整型,在32位机器上等同于int,在64位机器上等同于long

读取成功,则返回实际读取数据的字节数;

读取失败,则返回 -1。


利用系统接口读文件的例子:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
  int fd = open("myfile.txt", O_RDONLY);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }
  const char* msg = "hello world !\n";
  char buf[1024];
  while(1)
  {
    ssize_t s = read(fd, buf, strlen(msg));//类比write
    if(s > 0)
    {
      printf("%s", buf);
    }
    else
    {
      break;
    }
  }
  close(fd);
  return 0;
}

close

系统接口中使用close关闭文件,man手册中的close:

参数解读:

fildes:文件描述符

返回值:

关闭成功,则返回 0;

关闭失败,则返回 -1。

【Linux学习】基础IO2:https://developer.aliyun.com/article/1383893

目录
相关文章
|
11天前
|
Ubuntu Linux vr&ar
IM跨平台技术学习(十二):万字长文详解QQ Linux端实时音视频背后的跨平台实践
本文详细记录了新版QQ音视频通话在 Linux 平台适配开发过程中的技术方案与实现细节,希望能帮助大家理解在 Linux 平台从 0 到 1 实现音视频通话能力的过程。
32 2
|
2天前
|
Ubuntu 应用服务中间件 Linux
Linux学习之Ubuntu 20中OpenResty的nginx目录里内容和配置文件
总的来说,OpenResty的Nginx配置文件是一个强大的工具,它允许你以非常灵活的方式定义你的Web服务的行为。
8 2
|
3天前
|
Linux 数据处理 C语言
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
19 0
|
3天前
|
Linux 编译器 C语言
【Linux】基础IO----理解缓冲区
【Linux】基础IO----理解缓冲区
16 0
【Linux】基础IO----理解缓冲区
|
10天前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
|
18天前
|
安全 Linux
蓝易云 - Linux学习之RAID
以上就是Linux中RAID的基本概念和使用方法。
16 1
|
19天前
|
Linux 编译器 C语言
【Linux】基础IO_4
【Linux】基础IO_4
14 3
|
3天前
|
Linux C语言 C++
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(上)
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(上)
18 0
|
17天前
|
Unix 关系型数据库 Linux
技术笔记:linux学习心得
技术笔记:linux学习心得
12 0
|
18天前
|
网络协议 算法 Linux
技术笔记:Linux学习:TCP粘包问题
技术笔记:Linux学习:TCP粘包问题
15 0