Linux系统编程——文件I/O操作

版权声明:版权归博主所有,转载请注明 https://blog.csdn.net/qq_17808707/article/details/88034994

一 非缓冲文件操作

针对于小规模文件的读写,或者是实时设备,例如调制解调器、连接于串口的工业设备。执行非缓冲文件操作后,应用程序将立即获取或传送数据。
3个操作系统预先分配的文件标识符

  • 0:标准输入,即通过终端输入
  • 1:标准输出,即通过终端输出
  • 2:标准错误,系统中存放错误信息的堆栈

1.使用read()读取文件

read()函数用于从文件中将信息读取到指定的内存区域中。一般形式为:

read(文件标识符,内存块指针,内存块长度)
  • 文件标识符:用open()函数获得或预先分配
  • 内存块指针:指定函数读取数据的保存位置
  • 内存块长度

返回值是实际读取的长度,若返回值为0,表示没有读取任何数据,运行错误是返回1。
如下示例:

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

const int LENGTH=2000;

int main()
{
	char c[LENGTH];
	int f,i,j=0;
	f=open("/usr/include/gnu-versions.h",O_RDONLY,LENGTH);
	if(f!=-1)
	{
		i=read(f,c,LENGTH);
		if(i>0)
		{
			for(;i>0;i--)
				putchar(c[j++]);
		}
		else
			perror("读取");
	}
	else
		perror("打开文件");
	return 0;
}

编译并运行,结果如下:
在这里插入图片描述

2.使用write()写入文件

write()函数用于将指定长度的数据写入文件,一般形式为

write(文件标识符,内存块指针,内存块长度)

函数返回值是其实际写入的长度,如果返回0,表示没有写入任何数据,运行错误返回1。如下例所示:

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

const int LENGTH=2000;

int main()
{
	char c[LENGTH];
	int f,i;
	puts("输入要保存的文件信息:");
	if((i=read(0,c,LENGTH))<1)
	{
		perror("读取失败:");
		return 1;
	}
	f=open("outfile",O_RDWR|O_CREAT,0664);
	if(f!=-1)
	{
		if(write(f,c,i)!=i)
			perror("写入失败");
		puts("保存文件成功!");
		close(f);
	}
	else
		perror("打开文件");
	return 0;
}

该程序从文件标识符为0的设备读取数据,0是系统预定义的文件标识符,该标识符代表标准输入,即终端。
编译后运行结果如下图所示:
在这里插入图片描述

3.随机读写文件

open()函数内部有一个隐藏的文件指针位置,该指针指向文件正在读写的位置。在未指定的情况下,该位置处于文件的开始。如果在open()函数参数中加入副标志O_APPEND,那么打开文件时指针将指向文件末端,后一次输入的数据将保存在文件末尾。例如:

f=open("outfile",O_RDWR|O_CREAT|O_APPEND,0664);//打开或新建一个文件,从文件末端操作

如果要在程序运行中指定指针的具体位置,可使用lseek()函数实现。该函数的一般形式是:

lseek(文件标识符,偏移长度,起始位置);
  • 偏移长度:设置指针位置
  • 起始位置:定义指针位置的参考坐标,可用3个枚举常量表示,如下表

在这里插入图片描述
当起始位置为当前位置或文件末端时,偏移长度允许为负值,表示指针向前移动。但偏移长度不能超过文件的首尾限定范围。lseek()函数返回值是指针位置,操作失败返回-1。

二 缓冲文件操作

缓冲区是为程序分配的内存块,在进行数据量比较大且不要求实时性的I/O操作时,一部分数据被置于缓冲区中,只有当数据的长度快要超过缓冲区范围或时间周期达到时,这些数据才被送入指定位置。
基于缓冲区的文件I/O操作减少了对设备的物理数据接口访问次数,从而使大量数据的I/O操作的系统开支减少,将实际读写速度提升。
标准输入输出库定义了文件流结构指针FILE*作为文件的标识,同时提供了一系列缓冲文件操作函数。有3个文件流是系统预定义的,下面分别介绍:

  • stdin:标准输入
  • stdout:标准输出
  • dtderr:标准错误

打开与关闭文件流

打开文件流操作的函数是fopen(),该函数与系统调用函数open()的作用相似,主要用于文件和终端的输入输出方面,所以并不能对文件权限进行操作。该函数的一般形式是

fopen(路径,打开方式);

打开方式如下:
在这里插入图片描述
如果函数执行成功,返回文件流指针,否则返回NULL。
当文件不需要使用,可用fclose()函数将文件关闭。该函数的一般形式是:

fclose(文件流指针);

当fclose()函数执行时,所有放在缓冲区等待写入的数据都将被写入到文件中。如果数据未能被成功保存,fclose()函数返回-1,否则返回0。
用法参看如下示例:

#include<stdio.h>
int main()
{
	FILE *fp;
	fp=fopen("/usr/include/gnu-versions.h","r");
	if(fp!=NULL)
		puts("打开文件成功");
	else
	{
		perror("打开文件");
		return 1;
	}
	if(fclose(fp)!=-1)
		puts("关闭文件成功");
	else
	{
		perror("关闭文件");
		return 1;
	}
	return 0;
}

运行结果如下
在这里插入图片描述

2.读取与写入文件流

读取文件流可使用fread(),该函数的一般形式是:

fread(缓冲区指针,长度,数量,文件流指针);
  • 缓冲区:在程序中定义,定义后将指针作为参数传递给fread()函数
  • 长度:每次读取到缓冲区内存数据的长度
  • 数量:读取操作的最多次数

该函数的返回值是读取到缓冲区的次数,这个次数可能会小于参数中定义的最多次数。
如果文件的长度大于fread()函数实际读取数据的长度,那么实际读取数据的总和为参数中长度与数量的乘积。
写入文件流可使用函数fwrite(),该函数的形式与fread()相同。
如果待写入的数据存储在缓冲区中,而又要立即将缓冲区的数据写入文件,可使用fflush()函数实现。一般形式为:

fflush(缓冲区指针);

函数应用示例如下:

#include<stdio.h>
const long SIZE=65536;   //定义缓冲区大小,64KB
const int LENGTH=1024;   //定义每次读取的长度,1KB
int main()
{
	char buf[SIZE]={0};
	FILE *fp;
	fp=fopen("/usr/include/gnu-versions.h","r");
	if(fp!=NULL)
	{
		if(fread(buf,LENGTH,SIZE/LENGTH,fp)>=0)
			puts("读取文件成功");
		else
		{
			perror("读取文件失败");
			return 1;
		}
	}
	else
		perror("打开文件");
	fclose(fp);
	fp=fopen("copy","rw+");
	if(fp!=NULL)
	{
		if(fwrite(buf,LENGTH,SIZE/LENGTH,fp)>=0)
		{
			fflush(fp);
			puts("写入文件成功");
		}
		else
		{
			perror("写入文件失败");
			return 1;
		}
	}
	else
		perror("打开文件");
	if(fclose(fp)!=1)
		puts("关闭文件成功");
	else
		perror("关闭文件");
	return 0;
}

执行结果如下图所示:
在这里插入图片描述
copy文件内部如下所示:
在这里插入图片描述

3.文件流的格式化输入与输出

标准输入输出库里提供了文件流的格式化输入输出函数fscanf()和fprintf(),这两个函数的一般形式如下:

fscanf(文件流指针,"控制字符串",输入项列表);
fprintf(文件流指针,"控制字符串",输出项列表);

4.文件流的定位操作

文件流结构中有一个指针指向正在读写文件数据的位置。在操作文件流时,可通过调整该指针对文件的指定位置进行操作。fseek()函数与系统调用函数seek()的定义方法和使用几乎一致,只是fseek()函数第一个参数是文件流指针。除此之外,还有下列其他函数:
在这里插入图片描述
fpos_t类型是标准函数库中定义的一种结构体,也是文件流FILE结构体中的一个成员。

5.文件流操作的其他函数

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_17808707/article/details/88034994