通用的I/O模型(一)——文件的基本操作

一,概述:
所有的IO操作的系统的系统调用都是以文件描述符,一个非负整数来指代打开的文件,文件描述符用于表示所有类型的已打开文件,包括特殊文件(管道,socket套接字)等。
linuxshell操作中有三个默认的文件描述符

文件描述符用途
0标准输入
1标准输出
2标准错误

注:对应的POSIX接口分别为:STDIN_FILENO STDOUT_FILENO STDERR_FILENO,而相对应的流分别为stdin,stdout,stderr
如果调用POSIX标准名称则需要包含头文件<unistd.h>
注:linux I/O模型的显著特点之一是其输入和输出的通用性概念,这说明使用4个同样的系统调用open(),read(),write(),close()可以对所有类型的文件进行IO操作,包括终端设备如果
应用程序需要访问文件系统或设备的专有功能时,可以使用ioctl()系统调用,该调用为除了IO通用模型外提供了别的访问接口。
二,一些文件系统调用
1>open函数打开文件并且返回文件描述符

#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname,int flags/*mode_t mode*/*);/*mode为创建文件的权限比如0600,0666*/

pathname为符号链接,也就是文件路径。
flags为掩码指定问及那的访问形式,下表是常用的的

标志用途
O_RDONLY只读权限打开
O_WRONLY只写的权限打开
O_RDWR可读可写的权限打开
O_CREAT若文件不存在则创建
O_DIRECT无缓冲的输入输出
O_EXCL结合O_CREAT使用专门用于创建文件
O_NONBLOCK以非阻塞的方式打开

上表的常量分为三组:
*文件访问模式标志:可读可写,只读,只写只能选择一个,并且调用fcntl()的F_GETFL可以获取访问模式
*文件创建标志:创建O_CREAT等
*已打开的文件状态标志:使用fcntl()的F_GETFL和F_SETFL来检索和修改
2>使用creat()直接创建文件

#include<fcntl.h>
int creat(const char *pathname,mode_t mode);
注:若文件存在则打开文件,并且清空文件内容,将其长度请0,返回fd
和open使用open(pathname,O_WRONLY|O_CREAT|O_TRUNC,mdoe);

3>使用read()函数调用

#include <unistd.h>
ssize_t read(int fd,void*buf,size_t count);
/*read遇到\n等东西时候,read调用会停止
如果要读取带\n的东西时候需要追加\0*/

4>write函数

#include <unistd.h>
具体函数
ssize_t write(int fd,const void * buf,size_t n);

示例:
使用read函数和write函数简单实现对文件操作:

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


int main()
{
        int fd;
        char *buf = {"hello world"};
        fd = open("./file1",O_RDWR);
        if(fd == -1){

                printf("open file1 error\n");
                fd = open("./file1",O_RDWR|O_CREAT,0600);
                if(fd > 0){

                        printf("create file1\n");
                }
        }
        printf("open suceess! fd = %d\n",fd);

        int n_write = write(fd,buf,strlen(buf));
        if(n_write !=-1){
                printf("write %d byte success!\n",n_write);
        }

        close(fd);
        open("./file1",O_RDWR);

        char *buf2;
        buf2 = (char *)malloc(sizeof(char)*n_write + 1);
        int n_read = read(fd,buf2,n_write);

        printf("read %d , contant : %s\n",n_read,buf2);

        close(fd);
        return 0;
}

上面代码有一个缺陷二次读写是无法读到数据的,因为对于每个打开的文件来说,系统内核都会记录文件偏移量(有时称为读写偏移量或者指针),文件偏移量是执行下次read,write操作的文件首位置,会以相抵与文件头部起始点的文件当前位置来表示,文件第一个字节的偏移量为0;
5>lseek()函数改变文件偏移量
函数原型

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

 off_t lseek(int fd, off_t offset, int whence);
 /*函数掉用成功后会返回新的文件偏移量*/

offset指定了一个以字节为单位的数值,
whence参数如下:

意义
SEEK_SET将文件偏移量设置为相对于文件开头的offset个字节
SEEK_CUR相对于当前文件偏移量,将文件偏移量调整offset个字节
SEEK_END相对于文件尾部的offset个字节

使用lseek函数简单实现一个测试文件大小的demo

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


int main()
{
        int fd;
        char *buf = {"hello world!"};
        fd = open("./file1",O_RDWR);


        int filesize = lseek(fd,0,SEEK_END);
        printf("file is %d\n",filesize);

        close(fd);
        return 0;
}

三,通用IO模型外的操作

    #include <sys/ioctl.h>

     int ioctl(int fd, unsigned long request, ...);

注:常用于未纳入IO模型的所有设备。经常用于设备驱动等
四,几个简单的小demo
1>实现简单的复制

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


int main(int argc ,char **argv)
{
        int fdsrc,fddes;
        char *buf2 = NULL ;
        if(argc != 3){
                printf("error\n");
                exit(-1);
        }


        fdsrc = open(argv[1],O_RDWR);
        int size = lseek(fdsrc,0,SEEK_END);
        buf2 = (char *)malloc(sizeof(char)*size + 8);

        lseek(fdsrc,0,SEEK_SET);
        int n_read = read(fdsrc,buf2,size);


        fddes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);

        int n_write = write(fddes,buf2,n_read);

        close(fdsrc);
        close(fddes);

        return 0;
}

2>写入一些特殊的数据,比如结构体

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


struct test{
        int a;
        char c;


};
//linke read one by one
int main()
{
        int fd;
        struct test data[2] ={{ 100,'a'},{101,'b'}};
        struct test data2[2];

        fd = open("./file1",O_RDWR);

        int n_write = write(fd,&data,sizeof(struct test)*2);

        lseek(fd,0,SEEK_SET);
        int n_read = read(fd,&data2,sizeof(struct test)*2);
        printf("data2 = %d\n",data2[0].a);
        printf("data2.c = %c\n",data2[0].c);
        printf("%d %c\n",data2[1].a,data2[1].c);


        close(fd);

        return 0;
}
~                                                        

3>标准库的操作(使用fopen(),fclose(),fread(),fwrite()等)

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


struct test{
        int a;
        char c;


};

int main(int argc ,char **argv)
{
        FILE *fp;
        struct test data ={ 100,'a'};
        struct test data2;

        fp = fopen("./file1","w+");

        int n_write = fwrite(&data,sizeof(struct test),1,fp);

        fseek(fp,0,SEEK_SET);//相当于lseek函数,改变文件偏移量
        int n_read = fread(&data2,sizeof(struct test),1,fp);
        printf("data2 = %d\n",data2.a);
        printf("data2.c = %c\n",data2.c);

        fclose(fp);

        return 0;
}
~                                                   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值