(P4-P5)文件与IO:open、close、creat、read、write,errno的使用

2024-06-08 06:18

本文主要是介绍(P4-P5)文件与IO:open、close、creat、read、write,errno的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1.什么是I/O以及errno的使用
    • 2.文件描述符
    • 3.文件系统调用

1.什么是I/O以及errno的使用

  • 输入/输出是主存和外部设备之间拷贝数据的过程
    (1)设备——>内存(输入操作)
    (2)内存——>设备(输出操作)
  • 高级I/O:标准C库
    ANSI C提供的标准库称为高级I/O,通常也称为带缓冲的I/O
  • 低级I/O:系统调用IO
    通常也称为不带缓冲的I/O

2.文件描述符

  • 对于Linux而言,所有对设备或文件的操作都是通过文件描述符进行的
  • 当打开或者创建一个文件的时候,内核向进程返回一个文件描述符(非负整数)。
    后序对文件的操作只需通过该文件描述符,内核记录有关这个打开文件的信息。
  • 一个进程启动时,默认打开了3个文件,标准输入、标准输出、标准错误,对应文件描述符是0(STDIN_FILENO),1(STDOUT_FILENO),2(STDERR_FILENO),这些常量定义在unistd.h头文件中。
  • 注意:
标准C库访问文件,使用的是文件指针:FILE* fp
系统调用访问文件,使用int fp系统调用				  标准C库
STDIN_FILENO 		  stdin
STDOUT_FILENO 		  stdout
STDERR_FILENO 	      stderr
  • 代码:P4fileno.c
#include <stdlib.h>
#include <stdio.h>int main(void)
{printf("fileno(stdin) = %d\n", fileno(stdin));return 0;
}
  • 测试:
    该文件指针对应的文件描述符为0
    在这里插入图片描述

3.文件系统调用

  • open系统调用
    有几种方法可以获得允许访问文件的文件描述符。最常用的是使用open系统调用
1int open(const char *path, int flags);
参数:
path:文件的名称,可以包含(绝对和相对)路径
flags:文件打开模式返回值:
打开成功,返回文件描述符
打开失败,返回-12int open(const char *pathname, int flags, mode_t mode);
参数:文件的名称,可以包含(绝对和相对)路径
flags:文件打开模式
mode:用来规定对该文件的所有者,文件的用户组及系统中其它用户的访问权限
返回值:
打开成功,返回文件描述符;
打开失败,返回-1
  • 代码:P4open.c
    注意errno输出的三种方式
//下面的头文件来自man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>// #define ERR_EXIT(m) (perror(m), exit(EXIT_FAILURE))
//等价于下面的一条一句,注意斜杠后面不能有空格,前面可以有空格
#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)int main(void)
{int fd;//O_RDONLY只读方式打开fd = open("test.txt", O_RDONLY);if (fd == -1){fprintf(stderr,"open error with errno=%d_%s\n", errno, strerror(errno));//错误输出方法1perror("open error");//错误输出方法2ERR_EXIT("open error");//错误输出方法3exit(EXIT_FAILURE);//EXIT_FAILURE=1}printf("open succ\n");return 0;
}
  • 测试:
    在这里插入图片描述
  • 代码:P4open2.c
//下面的头文件来自man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)int main(void)
{umask(0);int fd;fd = open("test.txt", O_WRONLY| O_CREAT, 0666);if (fd == -1){ERR_EXIT("open error");exit(EXIT_FAILURE);}printf("open succ\n");return 0;
}
  • 测试:
    若注释掉umask(0),则与预期设置的0666不一样,这是由于umask造成的
    在这里插入图片描述
    666去掉022的权限(6的权限是4和2,去掉2的权限就是4),所以最终是644
    在这里插入图片描述
    新创建的文件的权限是0666
    在这里插入图片描述
  • 打开方式总结
    所有这些标志值的符号名称可以通过#include <fcntl.h>访问
    在这里插入图片描述
  • 代码:P4open3.c
//下面的头文件来自man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)int main(void)
{umask(0);int fd;//O_EXCL:如果文件存在则打开失败fd = open("test.txt", O_WRONLY| O_CREAT| O_EXCL, 0666);if (fd == -1){ERR_EXIT("open error");exit(EXIT_FAILURE);}printf("open succ\n");return 0;
}
  • 测试:
    不如数字创建方便
    S_IRUSR,S_IWUSR,S_IXUSR组合在一起就是7,其它以此类推
    在这里插入图片描述
  • 访问权限总结:下面的访问权限在man 2 open中
    在这里插入图片描述
  • 代码:P4open4.c
//下面的头文件来自man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)int main(void)
{umask(0);int fd;//创建600权限fd = open("test2.txt", O_WRONLY| O_CREAT| O_EXCL, S_IRUSR|S_IWUSR);if (fd == -1){ERR_EXIT("open error");exit(EXIT_FAILURE);}printf("open succ\n");close(fd);return 0;
}
  • 测试:
    在这里插入图片描述
  • open返回的错误码说明
若open返回的错误码是EMFILE
进程能够打开的文件数量
[root@host131 ~]# ulimit -n
1024若open 返回的错误码是ENFILE
系统能够打开的文件数量,与内存有关
[root@host131 ~]# cat /proc/sys/fs/file-max
179974
  • close系统调用
    为了重新利用文件描述符,用close()系统调用释放打开的文件描述符
int close(int fd);
参数:
fd:要关闭的文件的文件描述符返回值:
如果出现错误,返回-1;
调用成功返回0
  • creat系统调用
    为了维持与早期的UNIX系统的向后兼容性
int creat(const char *path, mode_t mode);参数:
path:文件的名称,可以包含(绝对和相对)路径
mode:用来规定对该文件的所有者,文件的用户组及系统中其它用户的访问权限返回值:
打开成功,返回文件描述符
打开失败,返回-1fd=creat(file,mode);
完全等价于近代的open()调用
fd=open(file, O_WRONLY|O_CREAT|O_TRUNC, mode);
  • read系统调用
    一旦有了与一个打开文件描述符相连的文件描述符,只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节
    man 2 read
ssize_t read(int fd, void *buf, size_t count);参数:
fd:想要读的文件的文件描述符
buf:指向内存块的指针,从文件中读取来的字节放到这个内存块中
count:从该文件复制到buf中的字节个数返回值:
如果出现错误,返回-1;
读文件结束,返回0;
否则返回从该文件复制到规定的缓冲区中的字节数
  • write系统调用:用write()系统调用将数据写到一个文件中
ssize_t与size_t的区别
size_t是无符号整数,可以看成unsigned int
ssize_t是有符号整数,可以看成是intssize_t write(int fildes, const void *buf, size_t nbyte);
函数参数:
fd:要写入文件的文件描述符
buf:指向内存块的指针,从这个内存块中读取数据写入到文件中
count:要写入文件的字节个数返回值:
如果出现错误,返回-1
如果写入成功,则返回写入到文件中的字节个数
  • ref:ssize_t和size_t的区别

  • read与write的区别?
    read操作表示将数据从磁盘读到缓冲区了
    write操作并不意味着缓冲区的数据写入到磁盘中,除非指定O_SYNC选项来打开(O_SYNC:写操作将被阻塞,直到数据被写入到物理硬件上面,才会返回),或者调用fsync()函数来进行同步

  • 代码:P5copy.c

//下面的头文件来自man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)//实现拷贝文件的功能
int main(int argc, char* argv[])
{int infd;int outfd;if (argc !=3 ){fprintf(stderr, "Usage %s src dts", argv[0]);ERR_EXIT(EXIT_FAILURE);}infd = open(argv[1], O_RDONLY);if (infd == -1)ERR_EXIT("open src error");if ((outfd = open(argv[2], O_WDONLY|O_CREAT|O_TRUNC, 0644)) == -1)ERR_EXIT("open dst error");//将infd的内容写入到outfdchar buf[1024];int nread;while ((nread = read(infd, buf, 1024) >0){write(outfd, buf, 1024);}close(infd);close(outfd);return 0;
}
  • 测试:
    在这里插入图片描述

  • 文件的随机读写
    (1)到目前为止的所有文件访问都是顺序访问。这是因为所有的读和写都是从当前文件的偏移位置开始,然后文件偏移值自动地增加到刚好超出读或写结束时的位置,使它为下一次访问做好准备
    (2)有个文件偏移机制,在Linux系统中,随机访问就变得很简单,你所需做的只是将当前文件移动改变到有关的位置,它将迫使一次read()或write()发生在这一位置。(除非文件被O_APPEND打开,在这种情况下,任何write调用仍将发生在文件结束处)

  • lseek
    对应C函数库的fseek(功能一致),目的是进行随机读写;
    功能:通过指定相对于开始位置、当前位置或末尾位置的字节数来重定位插入位置,这取决于lseek()函数中指定的位置

off_t lseek(int fd, off_t offset, int base);
参数:
fd:需设置的文件标识符
offset:偏移量
base:搜索的起始位置返回值:
返回新的文件偏移值
  • lseek中的搜索起始base位置
    定义在<unistd.h>
    在这里插入图片描述

  • 代码:P5lseek.c

//下面的头文件来自man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)int main(void)
{int fd;fd = open("test.txt", O_RDONLY);if (fd == -1)ERR_EXIT("open error");char buf[1024] = {0};int ret = read(fd, buf ,5);//读取5个字节到缓冲区,文件指针在5的位置if (ret == -1)ERR_EXIT("read error");printf("buf = %s\n", buf);//从当前指针所在位置偏移,偏移0个字节,返回值就是偏移量//该偏移量就等于当前指针所在的位置ret =lseek(fd, 0, SEEK_CUR);if (ret == -1)ERR_EXIT("lseek");printf("current offset = %d\n", ret);return 0;
}
  • 测试:
    当前偏移量为5
    在这里插入图片描述
    od -c XXX.txt查看空洞文件
    磁盘最小块单元是4k,查看方法du -h XXXX.txt
    在这里插入图片描述

  • 代码:P5hole.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)//空洞文件的eg
int mian(void)
{int fd;fd = open("hole.txt", O_WRONLY| O_CREAT| O_TRUNC, 0644);if (fd == -1)ERR_EXIT("open with error");write(fd, "ABCDE", 5);// int ret = lseek(fd, 32, SEEK_CUR);int ret = lseek(fd, 1024*1024*1024, SEEK_CUR);//仅仅在内核操作,不会在磁盘IO进行操作if (ret == -1)ERR_EXIT("lseek error");write(fd, "hello", 5);close(fd);return 0;
}
  • 测试:
    使用ls -lh查看的文件大小为1G多,实际在磁盘上的数据并没有1G多。实际上1G多的空洞文件并不存放在磁盘上,只保存必要信息
    一个文件的大小并不等于其在磁盘上所占用的空间
    在这里插入图片描述

  • opendir
    功能:打开一个目录

原型:
DIR *opendir(const char *name);参数:
pathname:文件的路径名,相对路径和绝对路径都行返回值:
打开成功,返回一个目录指针
打开失败,则返回0
  • readdir
    功能:访问指定目录中下一个连接的细节
struct dirent* readdir(DIR *dirptr);参数:
dirptr:目录指针返回值:
返回一个指向dirent结构的指针,它包含指定目录中下一个连接的细节;
没有更多连接时,返回0
  • closedir
    功能:关闭一个已经打开的目录
int closedir(DIr *dirptr)参数:
dirptr:目录指针
返回值:调用成功返回0,失败返回-1
  • 目录信息结构体

struct old_linux_dirent 
{long  d_ino;              /* inode number */文件在目录中的偏移位置off_t d_off;              /* offset to this old_linux_dirent */unsigned short d_reclen;  /* length of this d_name */文件名称的长度char  d_name[NAME_MAX+1]; /* filename (null-terminated) */
name最重要
}
  • 代码:P5ls.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#include <dirent.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)//编写简单的ls命令
int main(void)
{DIR *dir = opendir(".");//打开当前目录struct dirent *de;while ((de = readdir(dir)) != NULL)//man readdir{if (strncmp(de->d_name,"."1) == 0)continue;printf("%s\n", de->d_name);}close(dir);exit(EXIT_SUCCESS);//等价于exit(0);
}
  • 测试:
    在这里插入图片描述

  • 其它:
    mkdir系统调用:用来创建一个称为pathname的新目录,它的权限位设置为mode
    在这里插入图片描述
    rmdir系统调用:删除一个空目录
    在这里插入图片描述
    chmod和fchmod系统调用:用来改变给定路径名pathname的文件的权限位
    文件的路径名:绝对路径,or相对路径
    在这里插入图片描述
    chown和fchown系统调用:用来改变文件所有者的识别号(owner id)或者它的用户组识别号(group ID)
    在这里插入图片描述

  • Makefile

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01fileno 02open 03open 04open 05open 01cp 02lseek 03hole 04ls
all:$(BIN)
%.o:%.c$(CC) $(CFLAGS) -c $< -o $@
clean:rm -f *.o $(BIN)

这篇关于(P4-P5)文件与IO:open、close、creat、read、write,errno的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041400

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念