一、文件IO
操作系统为了方便用户使用系统功能而对外提供的一组系统函数。称之为 系统调用(unistd.h) 其中有个 文件IO,一般都是对设备文件操作,当然也可以对普通文件进行操作。
这是一个基于Linux内核的没有缓存的IO机制
文件IO特性:
.1 没有缓冲区
.2 操作对象不在是流,而是文件描述符
.3文件描述符
很小的非负的整数 int 0-1023
内核每打开一个文件就会获得一个文件描述符
每个程序在启动的时候操作系统默认为其打开
三个描述符与流对象匹配:
0 ==>STDIN_FILENO === stdin
1 ==>STDOUT_FILENO == stdout
2 ==>STDERR_FILENO == stderr
stdin,stdout,stderr,===>FILE*(标准IO)
注意:由于0,1,2被这三个描述符占了,所以我们写的文件描述符一般从3开始。
比较标准IO:
.1标准IO是C库中的,C库相比于系统调用,具有可移植性,也就是可以跨平台
.2标准IO提供了缓冲机制,例如全缓冲、行缓冲和无缓冲。
.3标准IO所使用函数,如fopen,fgets,fclose等,文件IO使用open,read,write,close等
.4标准 I/O 主要处理与标准输入、输出和标准错误相关的流。文件 I/O 可以处理各种文件,包括普通文件、设备文件等。
二、相关函数
1.open
int open(const char *pathname, int flags,int mode);
功能:获得一个文件描述符
参数:
pathname:文件名
flags:
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_CREAT 创建文件
O_TRUNC 文件内容清空
O_APPEND 追加
fopen与open对比
w O_WRONLY|O_CREAT|O_TRUNC
w+ O_RDWR|O_CREAT|O_TRUNC
r O_RDONLY
r+ O_RDWR
a O_WRONLY|O_CREAT|O_APPEND
a+ O_RDWR|O_CREAT|O_APPEND
返回值:
成功返回文件描述符
失败返回-1
eg:open("1.c",O_WRONLY|O_CREAT|O_TRUNC,0666 );
最后的0666是权限,与O_CREAT相对应,有创建就需要设置权限
注意:0666的前导零是不能省略的,这标志着0666是八进制,同时在创建目录和文件时,系统会与默认的umask(0002)相减,以便控制新建目标和文件有合理的权限。一般新建文件设置权限为0666,新建目录设置权限为0777;由于与umask相减,所以查看时,文件的权限会变成664(rw-rw-r--),目录权限会变成775(rwx rwx r-x)
2.write
ssize_t write(int fd, const void *buf, size_t count);
功能:通过文件描述符向文件中写一串数据
参数:
fd:文件描述符
buf:要写入文件的字符串的首地址
count:要写入字符串的实际长度
eg:
char buf[512]="hello";
write(fd,buf,strlen(buf));
注意:在write函数中count应该写buf里的字符串实际有效长度,这里使用了strlen计算字符串的长度,不能用sizeof(buf),因为sizeof计算出来的是所占空间的大小,是512字节,但是hello只有5字节,剩下的五百多字节就会补'\0',但文本文件中是不能有'\0'的。
返回值:
成功返回实际写入的个数
失败返回-1
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
int fd=open("open.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
if(fd==-1)
{
fprintf(stderr,"open error\n");
return 1;
}
printf("fd is %d\n",fd);//打印文件描述符
char buf[512]="bullish of shit";
int ret=write(fd,buf,strlen(buf));
if(ret==-1)
{
fprintf(stderr,"write error\n");
return 1;
}
close(fd);
return 0;
}
3.read
ssize_t read(int fd, void *buf, size_t count);
功能:通过文件描述符读取文件中的数据
参数:
fd:文件描述符
buf:存放数据空间的首地址
count:要读到数据的个数
注意:在read函数中count的值可以比实际的有效长度长,可以使用sizeof(buf)。
返回值:
成功返回读到数据的个数
失败返回-1
读到文件结尾返回0
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
int fd=open("open.txt",O_RDONLY);
if(fd==-1)
{
fprintf(stderr,"open error\n");
return 1;
}
printf("fd is %d\n",fd);
char buf[512]={0};
while(1)
{
int ret=read(fd,buf,sizeof(buf));
if(ret<=0)
{
break;
}
printf("%s\n",buf);
}
close(fd);
return 0;
}
4.lseek
off_t lseek(int fd, off_t offset, int whence);
功能:定位光标的位置
参数:
fd:文件描述符
offset:偏移量
正:向后偏移
负:向前偏移
零:不偏移
whence:
SEEK_SET
SEEK_CUR
SEEK_END
返回值:
成功返回偏移量,从文件开头开始,以字节为单位测量?
失败返回-1
通过lseek可以求文件大小
off_t off=lseek(fd,0,SEEK_END);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = open("backup.c",O_RDWR);
if(-1 == fd)
{
fprintf(stderr,"open error\n");
return 1;
}
off_t off = lseek(fd,15,SEEK_SET);
printf("off %ld\n",off);
char buf[]="hello";
write(fd,buf,strlen(buf));
printf("fd is %d\n",fd);
close(fd);
return 0;
}
5.fileno
int fileno(FILE *stream);
功能:
获得一个文件流指针中的文件描述符
可以认为是将文件流变为文件描述符 FILE* fp -> int fd
参数:
stream:文件流指针
返回值:
成功返回文件描述符
失败返回-1
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
FILE * fp=fopen("1.txt","r");
int fd=fileno(fp);
if(-1==fd)
{
fprintf(stderr,"flieno error\n");
return 1;
}
char buf[512]={0};
read(fd,buf,sizeof(buf));
printf("%s\n",buf);
fclose(fp);
return 0;
}
6.fdopen
FILE *fdopen(int fd, const char *mode);
功能:
将文件描述符转化为文件流指针 int fd -> FILE *fp
参数:
fd:已经打开的文件描述符
mode: "r"
"r+"
"w"
"w+"
"a"
"a+"
注意:原来的权限是O_RDONLY,对应"r",不能修改
返回值:
成功返回文件流指针
失败返回NULL
注意:fileno和fdopen使用封装度高的关闭文件,即fclose();
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
int fd=open("1.txt",O_RDONLY);
FILE *fp=fdopen(fd,"r");
if(NULL==fp)
{
fprintf(stderr,"fdopen error\n");
}
char buf[512]={0};
fgets(buf,sizeof(buf),fp);
printf("%s",buf);
fclose(fp);
return 0;
}
三、重点
open、read、write
使用read、write函数实现文件复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
if(argc<3)
{
fprintf(stderr,"usage:./a.out srcfile destfile\n");
return 1;
}
int src=open(argv[1],O_RDONLY);
int dest=open(argv[2],O_WRONLY | O_CREAT | O_TRUNC,0666);
if(src==-1 || dest==-1)
{
fprintf(stderr,"open error\n");
return 1;
}
printf("src is %d\n",src);
printf("dest is %d\n",dest);
while(1)
{
char buf[512]={0};
int ret=read(src,buf,sizeof(buf));
if(ret<=0)
{
break;
}
write(dest,buf,ret);
}
close(src);
close(dest);
return 0;
}