基于 C 语言 LINUX 的文件操作

基于 C 语言 LINUX 的文件操作

 作者:高玉涵
 时间:2022.2.8 10:20 (福虎年初八)
 博客:blog.csdn.net/cg_i

底层文件访问(Low-Level File Access)和文件描述符(File Descriptor)

 即使看到“底层”二字,也会有读者臆测其难以理解。实际上,“底层”这个表达可以理解为“与标准无关的操作系统独立提供的”。稍后讲解的函数是由 Linux 提供的,而非 ANSI 标准定义的函数。如果想使用 Linux 提供的文件 I/O 函数,首先应该理解好文件描述符的概念。

 此处的文件描述符是系统分配给文件的整数。实际上,学习 C 语言过程中用过的标准输入输出及标准错误在 LINUX 中也被分配表 1-1 中的文件描述符。

表 1-1 分配给标准输入输出及标准错误的文件描述符
文件描述符对象
0标准输入:Standard Input
1标准输出:Standard Output
2标准错误:Standard Error

 文件一般经过创建过程才会被分配文件描述符。而表 1-1 中的 3 种输入输出对象即使未经过特殊的创建过程,程序开始运行后也会被自动分配文件描述符。

打开文件

 首先介绍打开文件以读写数据的函数。调用此函数时必须传递的两个参数:第一个参数是打开的目标文件名及路径信息,第二个参数是文件打开模式(文件特性信息)。

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

int open(const char *pathname, int oflag, ... /* mode_t mode */);

 成功时返回文件描述符,失败时返回 -1 。
 ├── pathname 文件名的字符串地址。
 ├── oflag 文件打开模式信息。
 ├── mode O_CREAT 时需指定新文件访问权限位1

 表 1-2 是此函数第二个参数 oflag 可能的常量值及含义。如需传递多个参数,则应通过位或运算(OR)符组合传递。

表 1-2 文件打开械
打开模式含义
O_CREAT必要时创建文件
O_TRUNC删除全部现有数据
O_APPEND维持现有数据,保存到其后面
O_RDONLY只读打开
O_WRONLY只写打开
O_RDWR读写打开
关闭文件

 各位学习 C 语言时学过,使用文件后必须关闭。下面介绍关闭文件时调用的函数。

#include <unistd.h>

int close(int fd);

 成功时返回 0,失败时返回 -1 。
 ├── fd 需要关闭的文件或套接字的文件描述符。

 若调用此函数的同时传递文件描述符参数,则关闭(终止)相应文件。

将数据写入文件

 接下来介绍的 write 函数用于向文件输出数据。

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t nbytes);

 成功时返回写入的字节数,失败时返回 -1 。
 ├── fd 显示数据传输对象的文件描述符。
 ├── buf 保存要传输数据的缓冲地址值。
 ├── nbytes 要传输数据的字节数。

 此函数定义中,size_t 是通过 typedef 声明的 unsigned int 类型。对 ssize_t 来说,size_t 前面多加的 s 代表 signed,即 ssize_t 是通过 typedef 声明的 signed int 类型。

以 _t 为后缀的数据类型

 我们已经接触到 ssize_t、size_t 等陌生的数据类型。这些都是元数据类型(primitive),在 sys/types.h 头文件中一般由 typedef 声明定义,算是给大家熟悉的基本数据类型起了别名。既然已经有了基本数据类型,为何还要声明并使用这些新的呢?

 人们目前普遍认为 int 是 32 位的,因为主流操作系统和计算机仍采用 32 位。而在过去 16 位操作系统时代,int 类型是 16 位的。根据系统的不同、时代的变化,数据类型的表现形式也随之改变,需要修改程序中使用的数据类型。如果之前已在需要声明 4 字节数据类型之处使用了 size_t 或 ssize_t,则将大大减少代码变动,因为只需要修改并编译 size_t 和 ssize_t 的 typedef 声明即>可。在项目中,为了给基本数据类型赋予别名,一般会添加大量 typedef 声明。而为了与程序员定义的新数据类型加以区分,操作系统定义的数据类型会添加后缀 _t 。

 下面通过示例帮助大家更好地理解前面讨论过的函数。此程序将创建新文件并保存数据。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void error_handling(char *message);

int main(void)
{
  int fd;
  char buf[] = "Let's go!\n";
  
  fd = open("data.txt", O_CREAT|O_WRONLY|O_TRUNC, 0777);
  if( fd == -1 )
    error_handling("Open() error!");
  printf("file descriptor: %d \n", fd);
  
  if( write(fd, buf, sizeof(buf)) == -1 )
    error_handling("write() error!");
  close(fd);
  return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
  • 文件打开模式为 O_CREAT、O_WRONLY 和 O_TRUNC 的组合,因此将创建空文件,并只能写。若存在 data.txt 文件,则清空文件的全部数据。

 运行结果:low_open.c

gcc low_open.c -o lopen
./lopen
file descriptor: 3
cat data.txt
Let's go!
读取文件中的数据

 与之前的 write 函数相对应, read 函数用来输入数据。

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

 成功时返回接收的字节数(但遇到文件结尾则返回 0),失败时返回 -1 。
 ├── fd 显示数据传输对象的文件描述符。
 ├── buf 保存要传输数据的缓冲地址值。
 ├── nbytes 要接收数据的字节数。

 下列示例将通过 read 函数读取 data.txt 中保存的数据。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_SIZE 100
void error_handling(char *message);

int main(void)
{
  int fd;
  char buf[BUF_SIZE];
  
  fd = open("data.txt", O_RDONLY);
  if( fd == -1 )
    error_handling("Open() error!");
  printf("file descriptor: %d \n", fd);
  
  if( read(fd, buf, sizeof(buf)) == -1 )
    error_handling("read() error!");
  printf("file data: %s", buf);
  close(fd);
  return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

 运行结果:low_read.c

gcc low_read.c -o lread
./read
file descriptor: 3
file data: Let's go!

 基于文件描述符的 I/O 操作相关介绍到此结束。

引用


  1. Linux下用汇编语言处理文件(https://blog.csdn.net/cg_i/article/details/120725648?spm=1001.2014.3001.5501) ↩︎

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值