基于 Linux 的文件操作

1.文件描述符与套接字

对 Linux 而言,socket操作与文件操作没有区别,因而有必要详细了解文件。在 Linux 世界里,socket 也被认为是文件的一种,因此在网络数据传输过程中自然可以使用文件 I/O 的相关函数。

Linux 分配给标准输入、标准输出、标准错误的文件描述符如下表所示:

文件描述符对象
0标准输入:Standard Input
1标准输出:Standard Output
2标准错误:Standard Error

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

实际上,文件描述符只不过是为了方便称呼操作系统创建的文件或套接字而赋予的数而已。如果是 Windows 平台,则通常称之为“文件句柄”;如果是 Linux 平台,则通常称之为“文件描述符”。

在下面的程序 fd_seri.c 中,将同时创建文件和套接字,并用整数型态比较返回的文件描述符值。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>

int main(void)
{
	int fd1, fd2, fd3;
	
	// 创建1个文件和2个套接字
	fd1 = socket(PF_INET, SOCK_STREAM, 0);
	fd2 = open("test.dat", O_CREAT | O_WRONLY | O_TRUNC);
	fd3 = socket(PF_INET, SOCK_DGRAM, 0);
	
	// 输出之前创建的文件描述符的整数值
	printf("file descriptor 1: %d\n", fd1);
	printf("file descriptor 2: %d\n", fd2);
	printf("file descriptor 3: %d\n", fd3);
	
	close(fd1);
	close(fd2);
	close(fd3);
	
	return 0;
}

编译运行:

gcc fd_seri.c -o fds
./fds

输出结果:

file descriptor 1: 3
file descriptor 2: 4
file descriptor 3: 5

从输出的文件描述符整数值可以看出,描述符从 3 3 3 开始以由小到大的顺序编号,因为 0 0 0 1 1 1 2 2 2 是分配给标准 I/O 的描述符。

2.打开文件(open 函数)

调用 open 函数时需传递两个参数:第一个参数是打开的目标文件名及路径信息,第二个参数是文件打开模式(文件特性信息)。

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

int open(const char *path, int flag);

// 成功时返回文件描述符,失败时返回-1
// path:文件名的字符串地址
// flag:文件打开模式信息

下表是 open 函数第二个参数 flag 可能的常量值及含义。如需传递多个参数,则应通过位或运算符组合并传递。

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

3.关闭文件(close 函数)

使用文件后必须关闭。

#include <unistd.h>

int close(int fd);

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

若调用 close 函数的同时传递文件描述符参数,则关闭(终止)相应文件。另外需要注意的是,close 函数不仅可以关闭文件,还可以关闭套接字。这再次证明了“Linux操作系统不区分文件与套接字”的特点。

4.将数据写入文件(write 函数)

write 函数用于向文件输出(传输)数据。当然,Linux 中不区分文件与套接字,因此,通过套接字向其他计算机传递数据时也会用到该函数。

#include <unistd.h>

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

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

在上述 write 函数的定义中,size_t 是通过 typedef 声明的 unsigned int 类型。ssize_t 前面多加的 s 代表 signed,即 ssize_t 是通过 typedef 声明的 signed int 类型。

在下面的程序 low_open.c 中,将创建新文件并保存数据。

#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";
	
	// 文件打开模式为 O_CREAT、O_WRONLY 和 O_TRUNC 的组合,因此将创建空文件,并只能写。
	// 若存在data.txt文件,则清空文件的全部数据。
	fd = open("data.txt", O_CREAT | O_WRONLY | O_TRUNC);

	if (fd == -1)
	{
		error_handling("open() error!");
	}

	printf("file descriptor: %d\n", fd);

	// 向对应于fd中保存的文件描述符的文件传输buf中保存的数据
	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);
}

编译运行:

gcc low_open.c -o lopen
./lopen

运行上面的程序后,利用 Linux 的 cat 命令输出 data.txt 文件的内容为 Let's go!,可以确认确实已向文件传输数据。

5.读取文件中的数据(read 函数)

与前面的 write 函数相对应,read 函数用来输入(接收)数据。

#include <unistd.h>

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

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

在下面的程序 low_read.c 中,将通过 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];
	
	// 打开读取专用文件data.txt
	fd = open("data.txt", O_RDONLY);

	if (fd == -1)
	{
		error_handling("open() error!");
	}
	
	printf("file descriptor: %d\n", fd);
	
	// 调用read函数向第13行中声明的数组buf保存读入的数据
	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);
}

编译运行:

gcc low_read.c -o lread
./lread

输出结果:

file descriptor: 3
file data: Let's go!

基于文件描述符的 I/O 操作相关介绍到此结束。希望各位记住,该内容同样适用于套接字。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值