day27 文件IO

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;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值