1、文件IO(系统调用)
文件IO:基于系统调用的API函数接口。
特点:每一次调用文件IO,系统都会从用户态到内核态之间切换,效率很低。
作用:后期学习进程间通信,管道,SOCKET套接字通信,都会用到文件IO。
2、文件结构体
文件结构体成员 int _fileno就是打开文件后返回给用户的文件描述符。
struct _IO_FILE {
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
int _fileno;//文件描述符,也称为文件的句柄。
};
3、文件描述符:
1、本质上是一个非负整数,类似于标准IO打开文件时的 fp指针。
2、进程执行时默认打开3个文件描述符0(stdin),1(stdout),2(stderr)。
3、文件描述符可以使用ulimit -a查看打开文件个数。使用 ll 查看文件权限。
4、分配原则,按照最小未分配原则,而且每一个终端进程打开文件的个数是有限制的最多是1024个文件。
标准输入,标准输出,标准错误文件描述符
ubuntu@ubuntu:IO-2$ ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7558
max locked memory (kbytes, -l) 65536
max memory size (kbytes, -m) unlimited
open files (-n) 1024最多打开1024个文件
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7558
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

open和close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:打开或者创建文件。
参数1:文件的路径和文件名
参数2:打开或者创建文件时的语义
O_CREAT:创建文件
O_RDONLY:只读模式
O_WRONLY :只写模式
O_RDWR:读写模式
O_EXCL:如果文件存在就报错
O_TRUNC:清空文件内容。
O_APPEND:追加写的方式
以上选项可以按照位或方式组合使用。
参数3:可选项
如果参数2有O_CREAT或者O_TMPFILE,参数3必须加上创建时的权限,如果没有参
数3直接省略。
参数3是文件或者文件夹创建时的权限。
返回值:成功返回文件描述符,失败返回-1,并置位错误码。
文件夹的默认最大权限是775,文件的默认最大权限是664。
eg:
w:open("./1.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);
r:open("./1.txt",O_RDONLY);
r+:open("./1.txt",O_RDWR);
w+:open("./1.txt",O_CREAT|O_TRUNC|O_RDWR,0664);
a:open("./1.txt",O_CREAT|O_APPEND|O_WRONLY,0664);
a+:open("./1.txt",O_CREAT|O_APPEND|O_RDWR,0664);
还可以有以下使用规则:
open("./1.txt",O_CREAT|O_EXCL|O_RDWR,0664);//只创建读写文件,如果文件存在就报错。
open("./1.txt",O_CREAT|O_EXCL|O_TRUNC|O_WRONLY,0664);//只写创建,清空打开文件,如果文件存在就报错
int close(int fd);
功能:关闭open函数打开的文件描述符。
参数:文件描述符(文件句柄)
返回值:成功返回0,失败返回-1,并置位错误码。
文件夹的默认最大权限是775,文件的默认最大权限是664
如果我们在创建文件夹时给出的权限是777,那么由于终端的umask=0002,所以最终系统给的最大权限就是775.
如果我们在创建文件时给出的权限是666,那么由于终端的umask=0002,所以最终系统给的最大权限就是664.
write和read
ssize_t write(int fd, const void *buf, size_t count);
功能:向fd指向的描述符写入内容,写count个字节
参数1:文件描述符
参数2:写入的内容
参数3:写入的字节数。
返回值:成功返回写入的字节个数,如果什么都没写入返回0,失败返回-1,并置位错误码。
ssize_t read(int fd, void *buf, size_t count);
功能:从fd指向的文件读取count个字节到buf中
参数1:文件描述符
参数2:读取的内容
参数3:读取的字节数。
返回值:成功返回读取的字节数,读取到文件末尾返回0,失败返回-1,并置位错误码。
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fd;
fd = open("./1.txt",O_RDONLY);//只读方式打开文件
if(fd==-1)
{
perror("open");
return -1;
}
char buff[1024];
while(1)//循环读取文件内容
{
int res = read(fd,buff,sizeof(buff));
if(res==0)//读取到文件末尾结束读取
{
break;
}
printf("%s\n",buff);//输出读取的内容
}
close(fd);//关闭文件
fd = open("./1.txt",O_WRONLY|O_CREAT|O_TRUNC,0664);//只写创建清空方式打开文件
if(fd==-1)
{
perror("open");
return -1;
}
char s[100] = "唐明宇来自于广袤的原始森林";
int len = write(fd,s,strlen(s));//写入strlen(s)个字节
printf("写入%d个字节\n",len);
return 0;
}
练习一:只写方式打开文件,定义数组循环写入多个整数,再次只读方式打开文件,循环读取写入的整数,显示出来。
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fp=open("1.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);
int arr[4]={1,3,12,14};//定义数组
for(int i=0;i<4;i++)//循环写入数组元素
{
write(fp,&arr[i],sizeof(int));
}
close(fp);//关闭文件
int c;
fp=open("1.txt",O_RDONLY);//只读方式打开
for(int i=0;i<4;i++)//循环读取文件内容
{
read(fp,&c,sizeof(int));//读取到变量c中
printf("%d\t",c);//输出变量c
}
printf("\n");
return 0;
}
练习二:只写方式打开文件,定义结构体变量写入一个结构体变量,再次只读方式打开文件,读取写入的结构体变量显示出来。
#include <myhead.h>
typedef struct
{
int id;
char name[20];
}stu;
int main(int argc, const char *argv[])
{
stu a = {1001,"唐明宇"};//结构体变量
int fd = open("./3.txt",O_WRONLY|O_TRUNC|O_CREAT,0664);
if(fd==-1)
{
perror("open");
return -1;
}
int len = write(fd,&a,sizeof(stu));//结构体变量写入文件
printf("写入了%d个字节\n",len);
close(fd);
fd = open("./3.txt",O_RDONLY);//只读方式打开文件
if(fd==-1)
{
perror("open");
return -1;
}
stu b;
int res = read(fd,&b,len);//读取文件内容
printf("读取了%d个字节\n",res);
printf("%d\t%s\n",b.id,b.name);//输出
return 0;
}
练习三:实现文件的copy
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fd = open("./1.txt",O_RDONLY);
if(-1==fd)
{
perror("open");
return -1;
}
int fd2 = open("./2.txt",O_WRONLY|O_TRUNC|O_CREAT,0664);//打开文件2
if(-1==fd2)
{
perror("open");
return -1;
}
char buff[100];
while(1)
{
int res = read(fd,buff,sizeof(buff));//读取文件1
if(res==0)//读取到文件末尾
{
break;
}
write(fd2,buff,res);//写入文件2
}
printf("拷贝成功\n");
return 0;
}
lseek(fseek)
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fd = open("./1.txt",O_RDONLY);
if(-1==fd)
{
perror("open");
return -1;
}
int len = lseek(fd,0,SEEK_END);//光标移动到文件末尾返回光标到文件开头的字节数
printf("文件大小:%d\n",len);//1288
close(fd);//关闭文件
FILE *fp = fopen("./1.txt","r");//标准IO打开文件
if(NULL==fp)
{
perror("fopen");
return -1;
}
fseek(fp,0,SEEK_END);//光标移动到文件末尾
len = ftell(fp);//算出文件开头到光标之间的字节总数
printf("文件大小:%d\n",len);//1288
return 0;
}
dup和dup2
1、dup和dup2在赋值(复制)新描述符时新旧描述符都共享光标
2、dup会产生新的描述符遵循最小未分配原则
3、dup2不会产生新的描述符,只会先将新描述符指向的文件关闭,然后重定向新描述符到旧描述符文件。

#include <unistd.h>
int dup(int oldfd);
功能:将文件描述符拷贝一份生成新的描述符,新旧木薯淀粉指向同一个文件,并且共享文件光标。
参数:旧的描述符。
返回值:成功返回创建的新描述符,失败返回-1,并置位错误码。
int dup2(int oldfd, int newfd);
功能:将新的描述符重定向给旧的描述符,新的描述符指向的文件会被关闭,然后新
旧描述符都指向旧的文件,并且共享文件光标。
注意:dup2不会像dup那样产生新描述符并且也不会遵循最小未分配原则。
返回值:成功返回原本新描述符,但是新描述符值没有变化(重定向到旧的描述符),失败返回-1并置位错误码。
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fd = open("./1.txt",O_RDWR|O_CREAT|O_TRUNC,0664);
if(-1==fd)
{
perror("open");
return -1;
}
char buff[1024] = "abcdefg";
write(fd,buff,sizeof(buff));//写入数据
lseek(fd,0,SEEK_SET);//光标重新指向开头
int newfd = dup(fd);//使用dup产生新的描述符
lseek(newfd,3,SEEK_SET);//操作新描述符往后移动3个字节
read(fd,buff,sizeof(buff));//读取旧的描述符
printf("%s\n",buff);//defg
printf("fd = %d\nnewfd = %d\n",fd,newfd);//3,4
close(fd);
close(newfd);
return 0;
}
dup2
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fd1 = open("./3.txt",O_RDONLY);
if(fd1==-1)
{
perror("open");
return -1;
}
int fd2 = open("./4.txt",O_RDONLY);
if(fd2==-1)
{
perror("open");
return -1;
}
printf("fd1 = %d\nfd2 = %d\n",fd1,fd2);
int res = dup2(fd1,fd2);
printf("fd1 = %d\nfd2 = %d\nres = %d\n",fd1,fd2,res);
char buff[1024];
lseek(fd1,3,SEEK_SET);//操作fd1描述符将光标移动3个字节
read(fd2,buff,sizeof(buff));//读取fd2描述符
printf("%s\n",buff);
return 0;
}
作业:用read和write实现拷贝文件,将1.txt内容前一半拷贝给2.txt后一半拷贝给3.txt。
#include<myhead.h>
int main(int argc, const char *argv[])
{
int fd1,fd2,fd3 ;
fd1 = open("1.txt",O_RDONLY);
if(-1==fd1)
{
perror("open");
return -1;
}
fd2 = open("2.txt",O_WRONLY|O_CREAT|O_TRUNC,0664);
if(-1==fd2
{
perror("open");
return -1;
}
fd3 = open("3.txt",O_WRONLY|O_CREAT|O_TRUNC,0664);
if(-1==fd3)
{
perror("open");
return -1;
}
int len = lseek(fd1,0,SEEK_END);//计算出总字节数
int half = len/2;
lseek(fd1,0,SEEK_SET);//将光标置于开头开始读取
char a[1024];
char b[1024];
int c,d;
c = read(fd1,a,half);//读取字节数
write(fd2,a,c);//写入文件2
d = read(fd1,b,len-half);
write(fd3,b,d);
printf("拷贝完成\n");
return 0;
}
—
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fp1,fp2,fp3;
fp1=open("2.c",O_RDONLY);
fp2=open("2.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);
fp3=open("3.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);
if(fp1==-1||fp2==-1||fp3==-1)
{
perror("open");
return -1;
}
int len=lseek(fp1,0,SEEK_END);
lseek(fp1,0,SEEK_SET);
char a[500];
int b,q;
while(1)
{
b=read(fp1,a,sizeof(a));
if(q=lseek(fp1,0,SEEK_CUR)>=len/2)
{
int c=lseek(fp1,-sizeof(a),SEEK_CUR);
b=read(fp1,a,len/2-c);
write(fp2,a,b);
break;
}
write(fp2,a,b);
}
while(b=read(fp1,a,sizeof(a)))
{
write(fp3,a,b);
}
close(fp1);
close(fp2);
close(fp3);
return 0;
}
522

被折叠的 条评论
为什么被折叠?



