IO相关


—I/O(input/output)—

​ 分为 标准I/O 和 系统调用I/O(文件I/O)

定义

标准I/O

​ 标准I/O 是ANSIC 建立的一个标准I/O模型,都包含在头文件 stdio.h 里。具有一定的可移植性。

标准的IO提供了三种类型的缓存:
(1)全缓存:当填满标准IO缓存后才进行实际的IO操作。
(2)行缓存:当输入或输出中遇到新行符时,标准IO库执行IO操作。
(3)不带缓存:像stderr。

相关函数有 打开 fopen , 关闭 fclose , 读 getc,fgetc, gets, fgets, fread ,写 putc,fputc,puts,fputs, fwrite .

系统调用I/O

​ 系统调用I/O (文件I/O) ,也称之为不带缓存的IO(unbuffered I/O)。不带缓存指的是每个read,write都调用内核中的一个系统调用。

相关函数有 打开 open , 关闭 close , 读 read ,写 write

区别

  两者最显著的不同点在于:标准I/O默认采用了缓冲机制,比如调用fopen函数,不仅打开一个文件,而且建立了一个缓冲区(读写模式下将建立两个缓冲区),还创建了一个包含文件和缓冲区相关数据的数据结构(FILE *)。

响应速度:文件IO快
吞吐量:标准IO快

文件IO和标准IO 不能混用
标准IO有缓冲区,通常需要fflush刷新
文件IO无缓冲区,一有数据就写

函数

IO相关

fopen 与 open 打开文件

1.包含头文件 #include <stdio.h>

2.包含头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

​ 原型:
​ 1.FILE *fopen(const char *pathname, const char *mode);

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

​ 其中:
​ pathname 为文件路径
​ mode 为打开文件方式: r(只读,文件初), r+ (读写,文件初), w(只写,若文件有数据则清除后重写) a(追加写,文件尾 )
​ flags 为…
​ mode 为O_RDONLY(只读),O_WRONLY(只写),O_RDWR (可读可写)等/

返回值:
1.成功返回 FILE类型指针,失败返回 NULL 且有 errno ( perror();)
2.成功返回 文件描述符(不等于0), 失败返 回 -1 且有 errno .

fclose 与 close 关闭文件

1.包含头文件 #include <stdio.h>
2.包含头文件 #include <unistd.h>

​ 原型:
​ 1.int fclose(FILE *stream);

​ 2.int close(int fd);

​ 其中:
​ stream 为FILE文件流
​ fd 为文件描述符

​ 返回值:
​ 1.成功返回 0,失败返回 EOF 且有 errno (perror();)
​ 2.成功返回 0, 失败返回 -1 且有 errno .

fgets/gets 与 fputs/puts 标准io读写

char *fgets(char *buf, int n, FILE *fp)
char *gets(char *buf)
这两个函数都制定了缓存地址读入的行将送入其中,gets从标准输入读,而fgets从指定流读取。对于fgets必须指定缓存的长度n,此函数一直读到下一个新行为止,但不超过n-1如果读不完下次继续本行。
fputs(const char *strr, FILE *fp)
puts(const char *str)
函数fputs将一个以null符终止的字符串写到指定流,终止符null补写出。fputs并不一定产生一个新行。puts一定会产生一个新行

fread/read 与 fwrite/write 标准/文件IO读写

fgets() 有局限性,每次最多只能从文件中读取一行内容,因为 fgets() 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread() 函数;相应地写入函数为 fwrite()。

​ 头文件:
​ 1.3. #include <unistd.h>

​ 原型:

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

​ 2.size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );

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

​ 4.size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );

​ 其中:
​ fd 为文件描述符
​ ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。
​ size:表示每个数据块的字节数。
​ buf 为 缓冲区 即 指针,指向一段内存单元;
​ count:表示要读写的数据块的块数。
​ fp:表示文件指针。

理论上,每次读写 size * count 个字节的数据

​ 返回值:

​ 1.3. 成功 返回读写的块数,也即 count。失败返回 -1 且有 errno .

​ 2.4. 成功 返回读写的块数,也即 count。失败则返回值小于 count

fseek 与 lseek 文件内容指针定位

2.头文件:
#include <sys/types.h>
#include <unistd.h>

​ 原型:
​ 1.int fseek(FILE *stream, long offset, int whence);

​ 2.off_t lseek(int fd, off_t offset, int whence);

​ 其中:
​ stream 为FILE文件流
​ fd 为文件描述符
​ offset 为偏移量 通常为0
​ whence 为偏移相对位置:
​ SEEK_SET 文件首
​ SEEK_CUR 文件当前位置
​ SEEK_END 文件尾

​ 返回值:
​ 1.成功返回 0, 失败返回 -1 且有 errno .

​ 2.成功返回 指针定位位置 ,失败返回 -1 且有 errno .

fflush 刷新缓冲区

​ 原型:
int fflush(FILE *stream);
​ 其中:
​ stream 为FILE文件流

​ 返回值:
​ 成功返回 0, 失败返回 EOF 且有 errno .

dup2 拷贝(原子操作)

​ 头文件:
​ #include <unistd.h>

​ 原型:
int dup2(int oldfd, int newfd);

​ 其中:
​ oldfd 为旧的描述符
​ newfd 为新的描述符
​ 原理:
先关闭newfd,然后将原先oldfd 拷贝到新的 newfd 上 .
​ 返回值:
​ 成功返回 新的描述符 ,失败返回 -1 且有 errno .

代码实例

标准调用I/O

#include <iostream>
using namespace std;

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

#define PATH  "/home/shx/desc.txt" 
#define BUFSIZE 1024

int main()
{
    FILE *fp;
    char buf[BUFSIZE];

    //打开文件
    fp = fopen(PATH,"r");
    int len ;
    //获取fp里文件内容放入buf中
    while(fgets(buf,BUFSIZE,fp) > 0)
    {
        
        printf("%s",buf);
    }
    
    //关闭文件
    fclose(fp);
     
    return 0 ;
}    

系统调用I/O

#include <iostream>
using namespace std;

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

#define PATH  "/home/shx/desc.txt" 
#define BUFSIZE 1024
int main()
{

    int sfd,len,pos,ret;
    int buf[BUFSIZE];
    
    // 打开文件
    sfd = open(PATH,O_RDONLY);       
    //判断打开是否成功
    if(sfd < 0) 
    {
        if(errno != EINTR)
        {
            perror("Open():");
            exit(1);
        }
    }
    
    //放循环里读文件
    while(1)
    {
        //读文件内容
        len = read(sfd,buf,BUFSIZE);
        //判断文件内容
        if(len <0)
        {
            if(errno == EINTR)
                continue;
            perror("Read():");
            exit(1);
        }
        if(len == 0)
            break;
        pos = 0 ;
        //当len>0一直写文件
        while(len>0)
        {
            //在 1 终端上写内容
            ret =write(1,buf+pos,len);
            //判断写的内容
            if(ret <0)
            {
                if(errno == EINTR)
                    continue;
                perror("Write():");
                exit(1);
            }
            pos += ret;
            len -= ret;
        }
    }
    
    //关闭文件
    close(sfd);
     
    return 0 ;

}    

dup2 原子拷贝

#include <iostream>
using namespace std;


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

#define PATH "/tmp/out"
int main()
{
    int fd;
    
    fd = open(PATH,O_WRONLY|O_CREAT|O_TRUNC,0600);
    if(fd<0)
    {
        perror("open()");
        exit(1);
    }
    
    //关闭标准终端输出1,将fd拷贝在文件描述符1里。若fd本身等于1 , 不做任何事
    dup2(fd,1);
    
    //如果文件描述符不等于1,关闭1
    if(fd != 1 )
        close(fd);
    

    cout<<"Hello!"<<endl;
    
    exit(0);

}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 351134995@qq.com

×

喜欢就点赞,疼爱就打赏