unix环境高级编程——文件IO

2023-11-19

本期主题:
unix环境高级编程——文件IO



0.引言

在Unix系统中,对于大多数文件IO只需要用到5个函数:open、read、write、lseek、close。这些函数通常被称为不带缓冲的IO(unbuffered IO),与标准IO相对,不带缓冲的意思是当调用read、write时,都直接调用了内核的系统调用(system call)

1.文件描述符

对于内核而言,一切皆文件,所有打开的文件都通过文件描述符引用。
文件描述符是一个非负整数。当打开一个文件时,内核会向进程返回一个非负整数的文件描述符。举个例子,当读、写一个文件时,先用open返回一个文件描述符来描述该文件,并这个文件描述符作为参数传递给read、write。

按照惯例,UNIX的shell将标准输入与文件描述符0相关联,文件描述符1与标准输出相关联,文件描述符2与标准错误关联。
在/usr/include/unistd.h中定义标准输入、输出、错误
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

2.IO编程中常用的API接口

1.open函数

作用: 调用open函数可以打开或者创建一个文件,若打开成功,则返回一个最小的未被使用的文件描述符,若失败则返回-1
参数说明: int open(const char *pathname, int flags, …/ * mode_t mode */ );
arg1: *pathname: 文件的路径名
arg2: flags: 表明access mode,是只读、只写还是可读可写

在linux中,可用man 2 open来查询open函数的说明

gary@ubuntu:~/workspaces/0.Server_Workspace$ man 2 open

OPEN(2)                                                                   Linux Programmer's Manual                                                                  OPEN(2)

NAME
       open, openat, creat - open and possibly create a file

SYNOPSIS
       #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);

       int creat(const char *pathname, mode_t mode);

       int openat(int dirfd, const char *pathname, int flags);
       int openat(int dirfd, const char *pathname, int flags, mode_t mode);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       openat():
           Since glibc 2.10:
               _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
           Before glibc 2.10:
               _ATFILE_SOURCE

这里就不全部展开了,大家可以自己去查看一下

2.close函数

有open函数就会有对应的close函数

CLOSE(2)                                                                  Linux Programmer's Manual                                                                 CLOSE(2)

NAME
       close - close a file descriptor

SYNOPSIS
       #include <unistd.h>

       int close(int fd);

DESCRIPTION
       close()  closes  a  file  descriptor,  so that it no longer refers to any file and may be reused.  Any record locks (see fcntl(2)) held on the file it was associated
       with, and owned by the process, are removed (regardless of the file descriptor that was used to obtain the lock).

       If fd is the last file descriptor referring to the underlying open file description (see open(2)), the resources associated with the open file description are freed;
       if the descriptor was the last reference to a file which has been removed using unlink(2), the file is deleted.

3.read函数

调用read函数从打开文件中读取数据

SYNOPSIS
       #include <unistd.h>

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

DESCRIPTION
       read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.

       On  files that support seeking, the read operation commences at the current file offset, and the file offset is incremented by the number of bytes read.  If the cur‐
       rent file offset is at or past the end of file, no bytes are read, and read() returns zero.

       If count is zero, read() may detect the errors described below.  In the absence of any errors, or if read() does not check for errors, a read() with  a  count  of  0
       returns zero and has no other effects.

       If count is greater than SSIZE_MAX, the result is unspecified.

实际读到的字节可能会少于要求读的字节数,比如以下这种情况:
在读要求字节数之前已经到达了文件的尾端,

  • 例如这个文件只有10个字节,要求读100个字节,但实际只会返回10个字节;
  • 下一次再调用read时,会返回0,因为已经到了尾端;
    看个例子来帮助理解:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int fd, size, ret;
    char buf[100];
    fd = open("./temp", O_RDONLY);
    size = read(fd, buf, 100);
    printf("size is %d\n", size);
    size = read(fd, buf, 100);
    printf("size is %d\n", size);
}
gary@ubuntu:~/workspaces/0.Server_Workspace/2.Unix_Advanced_Program/1.Unix_IO/1.Unbufferd_IO$ od -c temp 
0000000   h   e   l   l   o       w   o   r   l   d   !  \n

gary@ubuntu:~/workspaces/0.Server_Workspace/2.Unix_Advanced_Program/1.Unix_IO/1.Unbufferd_IO$ ./a.out 
size is 13
size is 0

temp是我创建的一个普通文件,里面的内容是Hello world!,一共13个字节,第一次要求读100字节,但是文件只有13个字节,所以返回13,第二次read由于已经到达文件尾了,所以返回0。

linux可重定向的小技巧

  • “>”或”1>”输出重定向:把前面输出的东西输入到后边的文件中,会清除文件原有的内容
  • “>>”或”1>>” 追加输出重定向:把前面输出的东西追加到后边的文件尾部,不会清除文件原有的内容
  • “<”或”0<”输入重定向:输入重定向用于改变命令的输入,后面指定输入内容,后面跟文件名
  • “<<” 或 “0<<” 追加输入重定向:后面跟字符串,用来表示“输入结束”,也可用Ctrl + D 来结束输入

因此上面的例子也可以这么验证:

int main(void)
{
    int fd, size, ret;
    char buf[100];
    // fd = open("./temp", O_RDONLY);
    size = read(STDIN_FILENO, buf, 100);
    printf("size is %d\n", size);
}
gary@ubuntu:~/workspaces/0.Server_Workspace/2.Unix_Advanced_Program/1.Unix_IO/1.Unbufferd_IO$ ./a.out < temp 
size is 13

4.write函数

调用write函数向打开文件写数据

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

5.lseek函数

每个打开的文件都有一个"当前文件偏移量(current file offset)"

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

       off_t lseek(int fd, off_t offset, int whence);

DESCRIPTION
       The  lseek() function repositions the offset of the open file associated with the file descriptor fd to the argument offset according to the directive whence as fol‐
       lows:

       SEEK_SET
              The offset is set to offset bytes.

       SEEK_CUR
              The offset is set to its current location plus offset bytes.

       SEEK_END
              The offset is set to the size of the file plus offset bytes.

看一个例子,用od(1)命令来比较文件的差异

int main(void)
{
    int fd, size, ret;
    char test_buf[] = "ABCDEFG";
    char buf[100];
    fd = open("./temp", O_RDWR);
    size = read(fd, buf, 100);
    printf("size is %d\n", size);
    ret = lseek(fd, 20, SEEK_SET);
    if (ret == -1)
    {
        printf("cannot seek !\n");
    }
    else
        printf("seek OK!\n");
    write(fd, test_buf, sizeof(test_buf));
}

gary@ubuntu:~/workspaces/0.Server_Workspace/2.Unix_Advanced_Program/1.Unix_IO/1.Unbufferd_IO$ od -c temp 
0000000   h   e   l   l   o       w   o   r   l   d   !  \n  \0  \0  \0
0000020  \0  \0  \0  \0   A   B   C   D   E   F   G  \0
0000034

3.函数sync、fsync和fdatasync

unix系统实现在内核中设有缓冲区高速缓存,大多数的磁盘IO都通过缓冲区缓存。当我们向文件写入数据时,内核通常先将数据复制到缓冲区中,然后排入队列,最后晚些再写入磁盘,这种被称为延迟写。UNIX提供了这几种函数:

int fsync(int fd);
int fdatasync(int fd);
void sync(void);

通常被称为 update的系统守护进程会周期性调用sync函数,从而来保证定期冲洗内核的块缓冲区。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

unix环境高级编程——文件IO 的相关文章

  • 什么定义了类型的大小?

    ISO C 标准规定 sizeof char lt sizeof short lt sizeof int lt sizeof long 我在 BIT Linux mint 19 1 上使用 GCC 8 大小为long int is 8 我正
  • getline 之后返回到文件开头

    所以我已经从文件中读取了所有行 while getline ifile line logic 其中 ifile 是 ifstream line 是字符串 我的问题是我现在想再次使用 getline 并且似乎无法返回到文件的开头 因为运行 c
  • strtok() 使用安全吗[重复]

    这个问题在这里已经有答案了 我读到了很多负面的东西strtok 有人说它已经过时 有人说它不是线程安全的 等等 那么真相是什么 我可以使用吗strtok 它是线程安全的吗 Note 我正在使用 Visual C 您可以使用它 它是标准库的一
  • 如何通过覆盖 MSBuild 目标来防止外语资源生成?

    我正在致力于减少大型 C ASP NET 解决方案的编译时间 我们的解决方案使用通常的 resx 文件方法翻译成大约十几种外语 这些资源文件的解析和编译极大地减慢了我们的编译时间 并且是日常的挫败感 我知道可以创建自定义资源提供程序并摆脱
  • 头文件中实现的函数的静态与内联

    我想到的方式inline在 C 中用于链接 作用域 我把它放在同一个篮子里extern and static对于全局对象 通常 对于在头文件中实现的函数 我的首选解决方案是将其设为静态 In Foo h static void foo Do
  • 如何使用c#从数据桶中获取所有文档?

    如何获取数据桶中的所有文档 我尝试过一个示例 但我只能获得一个特定的文档 这是我的代码 CouchbaseClient oclient oclient new CouchbaseClient vwspace data bucket name
  • 我可以将 char 或 DateTime 设置为 null 吗?

    我可以将 null 设置为char数据类型 并且DateTime在 C 中 多谢你们 这是不可能的 它是一个值类型 使用 char myChar null DateTime myDate null 这相当于 Nullable
  • 无法将参数从 `const char *` 转换为 `char *`

    鉴于此代码 void group build int size std string ips Build the LL after receiving the member list from bootstrap head new memb
  • FluentAssertions ShouldNotThrow 无法识别异步方法/Func

    我正在尝试检查异步方法是否抛出具体异常 为此 我使用 MSTEST 和 FluentAssertions 2 0 1 我已经检查过这个关于 Codeplex 的讨论 http fluentassertions codeplex com wo
  • ASP.NET MVC 动作过滤器

    有谁知道即使在 CATCH 块中 ActionFilterAttribute 类的 OnResultExecuted 方法是否也会执行 ie CookiesActions public ActionResult Login Usuarios
  • ASP.net WebForms - 在标记中使用 GetRouteUrl

    我一直在尝试弄清楚如何将路由功能与 ASP net 4 0 WebForms 一起使用 我将一条路线添加到我的路线集合中 void Application Start RegisterRoutes RouteTable Routes voi
  • linq where 子句和 count 导致 null 异常

    除非 p School SchoolName 结果为 null 否则下面的代码将起作用 在这种情况下 它会导致 NullReferenceException if ExistingUsers Where p gt p StudentID i
  • 使用 dateTimePicker 在 DataGridView 中编辑日期

    我有一个DateTime我的 WinForms 中的专栏DataGridView 目前只能通过手动输入日期来编辑该字段 例如 2010 09 02 需要什么才能拥有一个DateTimePicker 或同等 用作编辑器 DataGridVie
  • 意外的 const 引用行为

    include
  • 如何重用具有稍微不同的 ProcessStartInfo 实例的 Process 实例?

    我有以下开始的代码robocopy https technet microsoft com en us library cc733145 aspx as a Process 我还需要进行数据库查询以确定每次需要复制哪些目录robocopy被
  • C - 获取外部IP地址

    我需要通过 C C 调用获取我的公共 IP 地址 我知道作为替代方案 我可以从 http whatismyip akamai com 等外部链接获取 我写了一个示例来获取外部IP地址 但我的程序没有返回外部 IP 地址 我正在获取内部 IP
  • 为什么 C++ 标准没有将 sizeof(bool) 定义为 1?

    Size of char signed char and unsigned char由 C 标准本身定义为 1 个字节 我想知道为什么它没有定义sizeof bool also C 03 标准 5 3 3 1 说 sizeof char s
  • Unity - 在生成时获取随机颜色

    我有一个小问题 我想在我的场景中生成四边形 它们都应该有红色或绿色作为材质 但 Random Range 函数只能是 int 我该如何解决它 void SpawningSquadsRnd rndColor 0 Color red rndCo
  • 使用C标准数学库精确计算标准正态分布的CDF

    标准 C 数学库不提供计算标准正态分布 CDF 的函数 normcdf 然而 它确实提供了密切相关的函数 误差函数 erf 和互补误差函数 erfc 计算 CDF 的最快方法通常是通过误差函数 使用预定义常量 M SQRT1 2 来表示 d
  • 检查一个数是否是完全平方数?

    我认为以下代码存在精度问题 bool isPerfectSquare long long n long long squareRootN long long sqrt n 0 5 return squareRootN squareRootN

随机推荐

  • c++中的时间处理(3)与sleep相关的时间函数

    1 Sleep 函数 头文件 Windows下为 windows h Linux下为 unistd h 注意 1 Sleep是区分大小写的 有的编译器是大写 有的是小写 2 Sleep括号里的时间 在windows下是已毫秒为单位 而Lin
  • MySQL性能分析工具的使用

    1 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候 该如何思考呢 这里把思考的流程整理成下面这张图 整个流程划分成了 观察 Show status 和 行动 Action 两个部分 字母 S 的部分代表观察 会使用相应的分析工具 字
  • AngularJS API

    AngularJS提供了如下的一下常用函数 API名称 描述 anguler lowercase 转换为小写字母 anguler uppercase 转换为大写字母 angular isString 是否为字符串 isNumber 是否为数
  • 常用的转义字符 C语言

    转义字符 转义字符是一种特殊的字符常量 以反斜线 开头 后跟字符 具有特定的含义 不同于字符原有的含义 故称 转义 字符 上表 转义字符 含义 n 回车换行 光标移到下一行的行首 r 回车 光标移到当前行的行首 把当前行前面全部删掉 t 制
  • 【pyqt5学习】——菜单栏(QMenu())、工具栏QToolBar学习

    目录 1 菜单栏 QMenu 一般在窗口顶部 1 创建菜单栏步骤 2 信号与方法 3 实操 2 工具栏 一般在菜单栏下方 1 创建步骤 2 方法与信号 信号 方法 3 实操示例 3 状态栏QStateBar 用于显示状态信息 一般在窗口底部
  • 微信开放平台接入问题

    1 errcode 40163 errmsg code been used rid xxxxx 原因 获取token时 使用的code码被二次使用 2 errcode 40249 errmsg this template msg has b
  • python中的unicode

    Python s Unicode string type stores characters from the Unicode character set In this set each distinct character has it
  • 怎么样不使用python做到图片爬虫呢?试试这个神奇软件吧

    1 首先在 主题 选项 选择你需要搜索的内容 2 填写需要下载的文件数量 这个需要留意 如果没有更改保存地址 那么会覆盖以前的文件 3 任意选择一个你想保存的地址 链接 https pan baidu com s 16yKPdUEC355j
  • Eureka迁移到Nacos之服务名称大小问题解决

    我们应用往Eureka中注册使用的名称以及应用内部通过Feign调用 使用的服务名称都是小写 如user service 但是注册到Eureka中后 应用的名称全部都是以大写的形式存储及展现 由于Eureka客户端对大小写的支持都是一样的
  • 前端工程化:模块化、包管理工具、打包工具(Webpack基本使用和优化)、前端性能监控

    目录 1 模块化 1 CommonJS AMD CMD 1 1 背景 1 2 CommonJS规范的核心变量 1 3 exports module exports 和require本质 1 4 exports和module exports的
  • 为什么有些Buck-Boost芯片没有输出负压?

    大家好 这里是大话硬件 今天分享一篇和Buck Boost拓扑相关的问题 也是在最开始接触Buck Boost芯片时 就在内心产生了疑问 在开始学习DC DC拓扑时 很多资料都说 非隔离型的DC DC拓扑常见的有3种 分别是Buck Boo
  • 破解sqlyog 30天试用限制

    安装sqlyog后 进入注册表编辑器 进入 HEYK CURRENT USER Software 找到以 括起来的那项 最新10 XX版本的是 8E919370 318F 4E5E 9EbE 9147B1DB66C9 不用去关注里面的值 右
  • ‘Web\xxx\node_modules\.bin\‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。internal/modules/cjs/loader.js:905throw err

    运行 npm run serve 报上面的错误 错误原因 文件夹名称中不能有
  • Python matplotlib作图时,设置横纵坐标轴数值以百分比(%)显示

    一 当我们用Python matplot时作图时 一些数据需要以百分比显示 以更方便地对比模型的性能提升百分比 二 借助matplotlib ticker FuncFormatter 将坐标轴格式化 例子 encoding utf 8 im
  • C语言:整型在内存中的存储及表示形式(附习题)

    我们都知道 一个变量的创建是要在内存中开辟空间的 而空间的大小是根据不同的类型而决定的 那么数据在开辟空间中是如何存储的呢 首先我们先了解以下概念 一 整数的表示形式 原码 反码 补码 计算机中的整数有三种表示方法 即原码 反码和补码 三种
  • Unity 使用LineRenderer连接2个物体

    1 在Hierarchy面板中创建2个GameObject A和B 这就是希望连接的2个物体 2 同理创建1个EmptyObject C 挂上LineRenderer组件 记得给Materials赋值 3 创建1个新的C 脚本LineMan
  • jenkins解决不能打印springboot启动日志问题

    背景 已经可以在jenkins打包部署 但不能显示springboot启动日志 导致springboot启动报错时 并不知道具体原因 还需要登录linux系统去查看原因 主要步骤 1 开启远程服务器日志 2 利用sed命令 结束tail命令
  • String类

    下面是关于String类1相关的知识点 关于Java JDK 中内置的一个类 java lang String 1 String表示字符串类型 属于引用数据类型 不属于基本数据类型 2 在java 中随便使用双引号括起来的都是String对
  • 计算机领域中随处可见的抽象

    想要管理多种具体的东西 那么需要遵守每种东西的规范 如果想要提供一种通用模式来对这些具体的东西统一管理 需要使用一种古老的技术 抽象 抽象是将多种具体的东西 管理时需要遵守的规范 的共同点抽取出来 放入到更高一层的抽象层 在抽象层不定义或少
  • unix环境高级编程——文件IO

    本期主题 unix环境高级编程 文件IO 文件IO 0 引言 1 文件描述符 2 IO编程中常用的API接口 1 open函数 2 close函数 3 read函数 4 write函数 5 lseek函数 3 函数sync fsync和fd