Linux文件IO

一、Linux文件IO接口

1、Linux 文件 io 接口 - open/close

在 Linux 系统下, 用于对文件操作的库函数叫做文件 I/O
主要包括 open()/close()/read()/write() /lseek() 相应的系统调用 (准确说法是对系统调用的封装的库函数)文件描述符是一个非负整数, 当打开一个已存在文件或者创建一个新文件时, 内核向进程返回一个文件描述符
每个程序运行后, 操作系统会默认打开三个文件 标准输入 标准输出 标准错误输出, 文件描述符分别为 0 , 1 , 2
标准输入对应的设备一般为键盘
标准输出与标准错误输出设备一般为显示器

open函数

函数示例:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

头文件说明:

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

参数说明:

pathname : 文件路径名

flags : 打开标志

  • O_RDONLY: 只读方式打开文件
  • O_WRONLY: 可写方式打开文件
  • O_RDWR: 读写方式打开文件
  • O_CREAT: 如果该文件不存在就创建一个新的文件,并用第三的参数为其设置权限
  • O_EXCL: 如果使用 O_CRATE 时文件存在, open() 报错
  • O_TRUNC: 如果文件已经存在,并且以读 / 写或只写成功打开, 并清零
  • O_APPEND: 以添加的方式打开文件,在打开文件的同时,文件指针指向文件末尾

mode:指定创建新的文件的默认权限

返回值:

  • 成功: 返回 文件描述符
  • 失败 : 返回 -1, 并将错误编码保存到 errno

通过只读的方式打开一个文件

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
int  main(int argc,char *argv[] ){

	int fd;
	if(argc==2){
	fd=open(argv[1],O_RDONLY);
	if(fd==-1){
	perror("Open:");
	}
	close(fd);//close函数关闭
	}


	return  0;
}

以只写的方式打开文件, 如果不存在则创建, 如果文件存在则截短

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

int  main(int argc,char *argv[] ){


	int fd;
	if(argc==2){
	fd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0644);
	if(fd==-1){
	perror("Open:");
	}
	close(fd);
	}


	return  0;
}

errno

是 Linux 操作系统中用于存储错误编码的全局变量, 错误编码在 Linux 系统中的定义如下:

函数头文件

#include <stdio.h>

函数原型

void perror(const char *s)

函数参数

  • s : 自定义字符串参数

  • 错误信息转换主要使用strerror()函数, 具体说明如下:

    函数头文件#include <string.h>
    函数原型char *strerror(int errnum)
    函数功能 :
    将错误编码转换成字符串信息,并返回该字符串的地址
    函数参数–errnum : 错误编码
    函数返回值:返回错误码转换之后的字符串 or “Unknown error nnn”
    使用 strerror 函数转换错误码

include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc,char *argv[]){ 
int fd; 
fd = open(argv[1],O_RDONLY,0644);
if (fd == -1) { 
fprintf(stderr,"open() : %s\n",strerror(errno)); 
return -1; 
} 
return 0;

}

2、Linux 文件 io 接口 - read/write/lseek

read函数

函数头文件:

#include <unistd.h>

函数原型:

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

函数参数

  • fd : 文件描述符
  • buf : 数据缓冲区
  • count : 能够读取的最大字节数

函数返回值

  • 成功 : 返回实际读取的字节数
  • 失败 : -1, 并将错误编码设置到 errno 中

wirte函数

函数头文件

#include <unistd.h>

函数原型

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

函数参数

  • fd : 文件描述符

  • buf : 缓冲区地址

  • count : 需要写入的字节数

函数返回值

  • 成功: 返回实际成功写入的字节数
  • 失败: 返回 -1, 并设置 errno

示例 : 通过 write 函数 使用标准输出来打印 Hello world

#include<stdio.h>
#include<unistd.h>
int main(int argc,char *argv[]){
	write(1,"helloworld",10);//标准输出是1
	return  0;
}

lseek函数

函数头文件

#include <sys/types.h>
#include <unistd.h>

函数原型

off_t lseek(int fd, off_t offset, int whence);

函数参数

  • fd : 文件描述符
  • offset : 偏移量, 可以为正数或者负数
  • whence : 偏移相对位置
    SEEK_CUR : 相对于文件当前偏移
    SEEK_SET : 相对于文件开始位置
    SEEK_END : 相对于文件尾偏移

函数返回值
成功: 返回 0
失败 : 返回 -1, 并设置 errno

示例:将一个字符串 “hello linux io” 写入到文件中,在读取出来

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[]){
int fd;
char rd_buff[64]={0};
char wr_buff[14]={"hello linux io"};
fd=open(argv[1],O_RDWR|O_CREAT);
if(fd==-1){
perror("Open(): ");
return -1;
}
ssize_t wbytes=write(fd,wr_buff,14);
if(wbytes==-1){
perror("Write():");
return -1;
}

lseek(fd,0,SEEK_SET);

ssize_t rdbytes=read(fd,rd_buff,wbytes);
if(rdbytes==-1){

perror("Read():");
return -1;
}

printf("%s\n",rd_buff);
close(fd);
return 0;
}

二、Linux标准IO接口

简介:标准 IO 是另外一套 IO 接口,具有如下特点:

  • 标准 I/O 是属于跨平台, 可以在 Linux、windows、mac os 上运行, 文件 IO 只能在Linux 平台运行
  • 标准 I/O 自带缓冲区,有更高的 IO 效率
  • 标准 IO 提供丰富的操作文本信息接口
  • 标准 IO 底层需要依赖于 文件 IO
  • 在 Linux 系统下, 标准 I/O 是属于 glibc 库的一部分

函数原型

int fprintf(FILE *stream, const char *format, …);

函数功能:将格式化数据写入到指定文件中
函数参数:
stream : 流对象指针
format : 格式字符串
示例 : 通过 stdout 与 stderr 进行输出

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
int  main(int argc,char *argv[] ){

	fprintf(stdout,"hello world\n");
	fprintf(stderr,"can't open file");
	while(1){}//死循环

	return  0;
}

注意:
在上述程序中, 将 ‘\n’ 去掉之后, 在添加一个死循环后, 则程序运行的结果则不同, 这里是与标准 I/O 的缓冲区有关系

标准 I/O 的缓存大小为 8192, 在系统中定义如下 (stdio.h):

一般标准 I/O 的分类为:
全缓存: 当相应的缓冲区已经装满数据时, 才进行一次 I/O 操作
行缓存: 当相应的缓冲区存储一行时,则进行一次 I/O 操作, stdout 就是行缓存
不缓存: 直接进行 I/O 操作, 不进行缓存, stderr 就是不缓存

一般情况下, 程序在结束时会自动刷新缓冲区,但是当程序还未结束时, 刷新缓冲区则需要调用fflush()函数

#include <stdio.h>
int main(void){ 
printf("hello.");
fflush(stdout); 
while(1){}
return 0;

}

1、Linux 标准 io - fopen/fclose

fopen函数

函数头文件:

#include <stdio.h>

函数原型:

FILE *fopen(const char *pathname, const char *mode);

函数功能:打开文件,并获取流对象指针

函数参数:
pathname : 路径名
mode : 打开模式(b:二进制)

  • r 或 rb : 打开只读文件,该文件必须存在
  • r + 或 r+b : 打开可读写的文件,该文件必须存在
  • w 或 wb : 打开只写文件,若文件存在则文件长度清为 0, 即会擦些文件以前内容。若文件不存在则建立该文件.
  • w + 或 w+b 或 wb+ : 打开可读写文件,若文件存在则文件长度清为零,即会擦些文件以前内容. 若文件不存在则建立该文件.
  • a 或 ab 以附加的方式打开只写文件。若文件不存在,则会建立该文件, 如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留

函数返回值:
成功 : 返回文件指针
失败 : 返回 NULL, 并设置 errno
函数头文件:

#include <stdio.h>

fclose函数

函数原型:

int fclose(FILE *stream);

函数功能:关闭已经打开的文件

函数参数:stream : 文件指针

2、Linux 标准 io - fgetc/fputc

fgetc函数

函数头文件:

#include <stdio.h>

函数原型:

int fgetc(FILE *stream)

函数返回值:
读取成功,返回读取字符的ASCII码值;
读取失败,返回EOF

fpuc函数

函数头文件:

#include <stdio.h>

函数返回值:成功 : 返回 实际读取的字符
失败 : 返回 EOF, 并设置 errno

函数原型:

int fputc(int c, FILE *stream);

函数参数:
c : 待写入的字符
stream : 文件指针
成功 : 返回 实际写入的字符
失败 : 返回 EOF, 并设置 errno

示例 : 实现 cat 命令功能, 将文件中的数据显示到 stdout 上

#include<stdio.h>
int  main(int argc,char *argv[] ){

	FILE *fd;
	char ch;
	fd=fopen(argv[1],"r");
	while(ch!=EOF){
	ch=fgetc(fd);
	fputc(ch,stdout);
	}
	fclose(fd);

	return  0;
}

3、Linux 标准io - fgets/fputs

fgets函数

函数头文件:

#include <stdio.h>

函数功能: 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内

函数原型:

char *fgets(char *s, int size, FILE *stream);

函数参数:
s : 缓冲区地址
size : 最大可读取大小
stream : 文件指针

函数返回值:

  • 成功 : 返回缓冲区的地址,当读到文件尾时 会返回 NULL
  • 失败 : 返回 NULL(不是EOF)

fputs函数

函数头文件:

#include <stdio.h>

函数原型:

int fputs(const char *s, FILE *stream);

函数返回值:

成功:返回一个非负数

失败:返回EOF

示例:使用fgets与fputs输出文件内容到stdout上

#include<stdio.h>
int  main(int argc,char *argv[] ){

	FILE *fd=NULL;
	char buff[64];
	fd=fopen(argv[1],"r");
//注意fgets的参数顺序
	while(fgets(buff,sizeof(buff),fd)){
	fputs(buff,stdout);
	}
	fclose(fd);

	return  0;
}

4、Linux 标准 io - 格式化输入输出 与时间获取

格式化输入输出

函数原型

int printf(const char *format, …);

函数原型

int fprintf(FILE *stream, const char *format, …);

函数参数
stream : 流对象指针
format : 格式字符串

函数原型

int sprintf(char *str, const char *format, …);//函数功能
将格式化数据输出到字符串缓冲区中

函数参数
str : 字符串缓冲区地址
format : 格式字符串地址

函数原型

int scanf(const char *format, …);

函数原型

int fscanf(FILE *stream, const char *format, …);//从文件中读取格式化的数据
int sscanf(const char *str, const char *format, …);//从字符串读取格式化数据

函数参数
str : 字符串地址
format : 格式字符串地址

示例:格式化写入文件

#include <stdio.h>
int main(int argc,char *argv[]){

	char buffer[64];
	int numa=10,numb=20,numc=30;
	FILE *fd=fopen(argv[1],"r+");
	if(fd==NULL){
	fprintf(stderr,"Open():");
	}
	fprintf(fd,"%d-%d-%d",numa,numb,numc);
	sprintf(buffer,"%d-%d-%d",numa,numb,numc);
	puts(buffer);

	fclose(fd);


return 0;
}

格式化读取文件

#include <stdio.h>

int main(int argc,char *argv[]){

	char buffer[64];
	int numa=0,numb=0,numc=0;
	FILE *fd=fopen(argv[1],"r");
	if(fd==NULL){
	fprintf(stderr,"Open():");
	}
	fscanf(fd,"%d-%d-%d",&numa,&numb,&numc);//从文件中读取该格式的内容赋值给numa,numb,numc
	sprintf(buffer,"%d-%d-%d",numa,numb,numc);
	puts(buffer);

	fclose(fd);


return 0;
}

时间获取

在 Linux 中获取主要需要以下两个步骤
Step 1 : 通过 time() 函数获取从 1970 年至今的秒数
Step 2 : 通过 localtime() 或者 ctime() 函数转换

函数头文件

#include <time.h>

函数原型:

time_t time(time_t *tloc);
struct tm *localtime(const time_t *timep);//将时间戳转换成本地时间,并存储到 struct tm 结构体变量中

struct tm 结构体:

struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
}

示例:获取当前时间并打印

#include<stdio.h>
#include<time.h>
int main(){
time_t t;
struct tm *p_datatime;
t=time(NULL);
p_datatime=localtime(&t);
printf("%d-%d-%d::%d::%d::%d\n",p_datatime->tm_year+1900,p_datatime->tm_mon+1,p_datatime->tm_mday,p_datatime->tm_hour,p_datatime->tm_min,p_datatime->tm_sec);


return 0;
}

5、二进制读写与文件定位

在标准 I/O 中, 用于进行二进制文件进行读写时需要调用fread与fwrite

fread函数

函数头文件

#include <stdio.h>

函数功能:从二进制文件中读取数据到缓冲区

函数原型:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

函数参数:

  • ptr : 缓冲区地址
  • size : 读取每个数据块的大小
  • nmemb : 读取数据对象的个数
  • stream : 文件指针

函数返回值:

成功 : 返回实际读取的数据对象的个数
失败: 当到达文件尾或者发生错误,返回较小的数据对象个数或者 0

fwrite函数

函数头文件

#include <stdio.h>

函数功能:将缓冲区中的数据写入到文件中

函数原型:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

函数参数

  • ptr : 缓冲区地址
  • size : 写入每个数据块的大小
  • nmemb : 写入数据对象的个数
  • stream : 文件指针

函数返回值

  • 成功 : 返回实际写入的数据对象的个数
  • 失败: 当到达文件尾或者发生错误,返回较小的数据对象个数或者 0

fseek函数

函数头文件

#include <stdio.h>

函数功能:对文件进行定位
函数原型

int fseek(FILE *stream, long offset, int whence);

函数参数

  • stream : 文件指针
  • offset : 偏移量
  • whence: 偏移相对位置
    SEEK_SET :相对于文件头
    SEEK_CUR : 相对于文件当前位置
    SEEK_END : 相对于文件尾

函数返回值
成功: 返回设置后的偏移位置
失败:返回 -1, 并设置 errno

示例 : 使用 fread 与 fwrite 存储一个浮点数组的数据到文件中

#include <stdio.h>

int main(int argc,char *argv[]){

    float numbers[5]={1.1,1.2,1.3,1.4,1.5};
	size_t  write_size,read_size;

	FILE *fd=fopen(argv[1],"w+");
	if(fd==NULL){
	fprintf(stderr,"Open():");
	}
	write_size=fwrite(numbers,sizeof(float),5,fd);
	if(write_size!=5){
	fprintf(stderr,"Write():");
}
float numbers2[5]={0.0};
fseek(fd,0,SEEK_SET);//修改位置偏移量
read_size=fread(numbers2,sizeof(float),5,fd);
if(read_size!=5){
fprintf(stderr,"Read():");
}
for(int i=0;i<5;i++){
printf("%f ",numbers2[i]);
}



	fclose(fd);


return 0;
}

示例:使用二进制读取文件复制图片

用fseek来测量这个图片一共有多少个字节:
1、把光标设置到文件的尾部。
2、接着使用ftell()函数来获取长度length。
3、把光标设置回文件的开头。
ftell()函数的作用是 获取文件的 当前指针位置 相对于 文件首地址 的 偏移字节数 ;
函数原型

#include <stdio.h>
long ftell(FILE *stream);
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define BYTE unsigned char
int main(){
BYTE *buffer;
FILE *rfd;
FILE *wfd;
rfd=fopen("./Vue.jpg","rb");
wfd=fopen("./temp.jpg","wb");
fseek(rfd,0,SEEK_END);//移动光标到结尾
int len=ftell(rfd);//计算文件长度
buffer=(BYTE *) malloc(sizeof(BYTE)*len);
fseek(rfd,0,SEEK_SET);
fread(buffer,sizeof(BYTE),len,rfd);
fwrite(buffer,sizeof(BYTE),len,wfd);


fclose(rfd);
fclose(wfd);
return 0;
}

也可以不使用ftell()函数测量文件长度

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

#define BYTE unsigned char
int main(){
BYTE buffer[64]={0};
FILE *rfd;
FILE *wfd;
rfd=fopen("./Vue.jpg","rb");
wfd=fopen("./temp.jpg","wb");




while(fread(buffer,sizeof(BYTE),sizeof(buffer),rfd)){
fwrite(buffer,sizeof(BYTE),sizeof(buffer),wfd);
}



fclose(rfd);
fclose(wfd);
return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值