POSIX标准下的非缓冲类型的I/O流(Unix或Linux)

POSIX标准下的非缓冲类型的I/O流(Unix或Linux)

首先在这里先介绍一下什么是全缓存,行缓存以及无缓存的这几种类型;便于区分

标准C的io缓存类型:
全缓存:
    要求填满整个缓存区后才进行I/O系统调用操作,对于磁盘文件通常使用全缓存访问
行缓存:
    涉及一个终端时,使用行缓存
    行缓存满自动输出
    碰到换行符自动输出
无缓存:
    标准错误流stderr通常是不带缓存去的,这使得错误信息能够尽快的显示出来

在前面的博客中其实已经介绍了,关于标准C下的I/O流相关的操作,
其实在标准C中的IO流都是带有缓存的IO流形式,是对原来内核提供的无缓存的IO又进行了一次加缓存的封装,遵循的是ISO标准,而内核所提供的IO流都是遵循的是POSIX标准

 标准C的IO函数最终还是去调用内核提供的读写的函数
 标准库函数:
     遵循ISO标准,基于流的I/O,对文件指针(FILE结构体)进行操作
 系统调用
     兼容POSIX标准,基于文件描述符的IO,对文件描述符进行操作

在标准C中,我们最主要用到的就是FILE*,文件指针类型,但是在系统调用中,可能就并没有这样的一个文件指针类型,而是用另外一种文件描述符fd来进行代替
下面就先来说说系统调用中的文件描述符的概念:

   文件描述符:
    一个非负的整数,当打开或创建一个新文件时,内核向进程返回一个文件描述符,当读写一个文件时
    用open,creat返回的文件描述该文件,将其作为参数传递给read或write函数
    在posix应用程序中,证书0,1,2被替换成符号常数

    STDIN_FILENO
    STDOUT_FILENO
    STDERR_FILENO
    这些都在unistd.h头文件中
    目前Linux下文件描述符的范围是1024;

文件描述符与文件指针之间的相互转换关系如下所示:

    文件描述符与文件指针:
    fdopen()
        FILE *fdopen(int fd,const char  *mode);
        将文件描述符转换成文件指针

    fileno()
        int fileno(FILE *fp);
        将文件指针转换成文件描述符fd

后面会依次的介绍相关系统调用的下列相关相关函数

open();     打开文件
create();    创建文件
close();    关闭文件
read();        读文件
write();    写文件
lseek();    文件定位

1:open()函数

open函数的调用;
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

int open(const char*pathname,int flags);
int open(const char *pathname,int flag,mode_t mode);

参数:
    pathname:要打开或者创建文件的路径
    flags:  //如果同时去使用 ,用按位或|来进行参数组合
        O_RDONLY   只读
        O_WRONLY   只写
        O_RDWR     读写
        O_APPEND   追加,在网络文件系统中进行操作没有保证
        O_CREAT    如果指定文件不存在,则按照mode参数制定的文件权限来创建文件
        O_EXCL    如果同时指定了O_CREAT,并且文件已存在,则出错返回。
        O_DIRECTORY 如果path不是一个目录,读写出错
        O_TRUNC   如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断(Truncate)为0字节(清空)
        O_NONBLOCK  (非阻塞形式)如果pathname值的是一个FIFO一个块特殊文件或一个字符特殊文件,
        则此选项为此文件的本次 打开操作和后续的IO操作设置非阻塞方式
    mode:
        新建文件的访问权限,对于open函数而言,仅当创建新文件时才使用第三个参数(创建新文件的时候用到第三个参数),655,777,755,

    返回:
        文件描述符

2:creat()函数:

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

int creat(const char *pathname,mode_t mode);
返回:若成功为只写打开的文件的描述符,若出错为-1
功能创建一个新文件

    此函数等效于:
    open(pathname,O_WRONLY | O_CREAT |O_TRUNC,mode);
    creat的一个不足之处就是它以只写方式打开所创建的文件,创建成功的文件只能写

3:close()函数:

#include<unistd.h>
int close(int fd);
返回:若成功为0,若出错为-1;
功能:关闭一个打开的文件

参数:fd 已打开的文件描述符,
当一个进程终止时,它所有的打开文件都由内核自动关闭

4:read()函数

read函数:
#include<unistd.h>
ssize_t read(int fd, void* buf,size_t count);

返回:读到的子节数,若已到文件尾为0,若出错为-1
功能;从打开文件中读数据
参数:
    fd 读取文件的文件描述符
    buf 存放读取数据的缓存
    count 要求读取一次数据的子节数

有多种情况可使实际读到的子节数少于要求读子节数:
    读普通文件的时候,在读到要求子节数之前已到达文件尾部
    从终端设备读时,通常一次最多读一行
    当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的子节数
    某些面向记录的设备
    进程由于信号造成中断

读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数

5:write函数:

#include<unistd.h>
ssize_t write(int fd,const void* buf,size_t count);
返回:若成为已写的字节数,若出错为-1
功能:
向打开的文件中写数据

参数:
    fd 写入文件的文件描述符
    buf 存放待写数据的缓存
    count 要求写入一次数据的子节数

其返回值通常与参数count的值不同,否则表示出错
write出错的一个常见原因是:
    磁盘已写满,或者超过了对一个给定进程的文件长度限制
  对于普通文件,写操作从文件的当前位移量处开始,如果在打开该文件时,指定了O_APPEND选项
  则在每次写操作之前,将文件为以来设置在文件的当前结尾处,在一次成功写之后,该文件位移量增加实际写的字节数。

6:lseek函数:

#include <sys/types.h>
#include<unistd.h>
offset lseek(int fd,off_t offset, int whence);
返回:若成功则返回心的文件位移量,若出错为-1
功能:定位一个已打开的文件
参数:
    fd:已打开文件的文件的文件描述符号
    offset :位移量,是long类型的,所以返回的时候要使用%ld
    whence:定位的位置
        SEEK_SET:将该文件的位移量设置为距文件开始处offset个字节
        SEEK_CUR:将文件的位移量设置为其当前值加offset,offset正负都可以
        SEEK_END:将该文件的位移量设置为文件长度加offset,offset可为正负


lseek也可用来确定所设计的文件是否可以设置位移量。如果文件描述符引用的是一个管道或者FIFO,则lseek返回-1,并且将errno设置为EPIPE。
每个打开文件都有一个与其相互关联的“当前文件偏移量”,
它是一个非负整数,用以度量从文件开始处计算的字节数。
通常读写操作都是从当前文件偏移量出开始,并使偏移量增加所读或写的字节数,
按系统默认,当打开一个文件时,除非制定O——APPEND选项,否则该位移量设置为0;

使用lseek可以计算出文件的长度:
    lseek(fdin,0L,SEEK_END);

下面提供一个设置缓存相关的命令。缓存设置的好的话,可以提高文件的读写的效率

od -c 文件名字   //查看文件的ascii编码
如:od -c file.txt 
df -k
sudo tune2fs -l /dev   //通过网络查找磁盘块的大小,便于我们去设置我们的缓存
查看相关block的参数。如果block为4096的话,那么说明缓存最合适就是4096,如果是1024 则最合适的缓存就是1024

接下来就是上述函数的代码段部分了,很简单的文件拷贝函数代码是可以直接进行run的
1:io.h

#ifndef __IO_H__
#define __IO_H__

/**
*拷贝函数
*/
extern void copy(int  fdin,int fdout);

/**
*使用lseek函数来创建空洞文件
*/
extern void writeNullFile(int fdout);
#endif

copy.c

#include<unistd.h>
#include"io.h"
#include<malloc.h>
#include<stdio.h>
#include<errno.h>
#include<sys/types.h>

#define BUFFER_SIZE 1024
char * str = "7777799900876555";
#define OFFSET 10
/**
*关于文件的拷贝函数
*
*/
extern void copy(int fdin,int fdout){
    ssize_t size_in;
    ssize_t size_out;
    char* buffer = (char*)malloc(BUFFER_SIZE*sizeof(char));

    while((size_in = read(fdin,buffer,BUFFER_SIZE)) != 0){
        if(size_in > 0){
            fprintf(stdout,"read success\n");
            size_out = write(fdout,buffer,size_in);
            if(size_out > 0){
                fprintf(stdout,"write success\n");
            }else{
                fprintf(stderr,"write error:%s\n",strerror(errno));
            }
        }else{
            fprintf(stderr,"read error:%s\n",strerror(errno));
        }
    }

    free(buffer);
}

/**
*在原来拷贝过后的文件后面创建空洞文件,隔去一些空白的字节后,然后再去写
*SEEK_CUR 从当前位置开始定位
*SEEK_END 从结束开始定位
SEEK_SET   从开始的位置
*/
extern void writeNullFile(int fdout){
    lseek(fdout,OFFSET,SEEK_END);
    ssize_t size_out;
    size_out = write(fdout,str,sizeof(str)/sizeof(char));

    if(size_out >0){
        fprintf(stdout,"write success\n");
    }else{
        fprintf(stdout,"write error\n",strerror(errno));
    }
}

copy_test.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include "io.h"
#include<fcntl.h>
int main(int argc,char* argv[]){
    if(argc != 3){
        fprintf(stderr,"缺少参数数量\n");
        exit(EXIT_FAILURE);
    }
    int fdin;
    int fdout;

    fdin = open(argv[1],O_RDONLY);
    if(fdin < 0){
        fprintf(stderr,"open read file error\n");
        exit(EXIT_FAILURE);
    }else{
        fprintf(stdout,"open read file success\n");
    }

    fdout = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC,0777);
    if(fdout < 0 ){
        fprintf(stderr,"open or creat write file failed\n");
        exit(EXIT_FAILURE);
    }else{
        fprintf(stdout,"open or creat write file successed\n");
    }

    printf("fdin:%d,fdout:%d\n",fdin,fdout);
    copy(fdin,fdout);

    writeNullFile(fdout);   
    close(fdin);
    close(fdout);
    return 0;
}

代码拷贝下来是可以直接run的

在最后谢谢 大家的观看,写的不好的,或者错误的,请各位看官不腻赐教,不懂的地方,也可以相互交流,这也是在记录自己的成长过程的一种方式,谢谢,欢迎持续访问博客:会有更多精彩的

欢迎继续访问,我的博客

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POSIX API(Portable Operating System Interface)是一组操作系统API标准,用于确保可移植性。这些API包括文件 I/O 操作方法,可以在不同的操作系统上使用相同的语法进行文件操作。下面是一些文件 I/O 操作方法: 1. 打开文件: ``` int open(const char *path, int flags); // 返回文件描述符 ``` `open()` 函数用于打开文件,并返回文件描述符(file descriptor),这个文件描述符被用来在后续的文件操作中标识文件。参数 `path` 是文件路径,参数 `flags` 是打开文件的模式,比如 `O_RDONLY` 表示只读,`O_WRONLY` 表示只写,`O_RDWR` 表示读写等。 2. 写文件: ``` ssize_t write(int fd, const void *buf, size_t count); // 返回成功写入的字节数 ``` `write()` 函数用于将数据写入文件。参数 `fd` 是文件描述符,参数 `buf` 是要写入的数据缓冲区,参数 `count` 是要写入的字节数。函数返回成功写入的字节数。 3. 读文件: ``` ssize_t read(int fd, void *buf, size_t count); // 返回成功读取的字节数 ``` `read()` 函数用于从文件中读取数据。参数 `fd` 是文件描述符,参数 `buf` 是存储读取数据的缓冲区,参数 `count` 是要读取的字节数。函数返回成功读取的字节数。 4. 关闭文件: ``` int close(int fd); // 返回0表示成功 ``` `close()` 函数用于关闭文件。参数 `fd` 是文件描述符。函数返回0表示成功关闭文件。 以上是 POSIX API 中文件 I/O 操作的几个基本方法,还有一些其他的方法,如 `lseek()` 用于改变文件读写位置, `fstat()` 用于获取文件状态等。在实际的文件操作中,需要根据实际需求选择合适的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值