APUE 1 文件I/O

本章讨论不带缓冲的I/O, 代码实现采用golang的syscall包,其通常会包装一层系统调用不过大体相似


1.文件描述符(FD)

  • 文件描述符是一个非负的整数,内核通过该描述符对文件进行引用,进行与文件相关的操作

  • open、openat、creat函数会返回文件描述符

  • 已打开文件在内核的数据结构如图


    已打开文件
    • 进程表项:1.文件描述符标志 2.指向文件表项的指针
    • 文件表项:1.文件状态标志(读、写、同步等) 2.当前文件offset 3.指向v节点指针
    • v节点表项:1文件类型和对此文件进行操作的函数指针 2.i节点指针
    • i节点:文件长度,所有者、磁盘实际位置

2.打开文件open和openat

func Open(path string, mode int, perm uint32) (fd int, err error)
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)

这两个函数在使用上的区别体现于dirfd参数和path参数,存在三种可能性:

  • 当path为绝对路径时,dirfd被忽略,二者相同
  • 当path为相对路径时,dirfd指出了相对路径的开始地址(所在目录的文件描述符)
  • 当path为相对路径时,dirfd=_AT_FDCWD,则dirfd指向当前程序的工作目录
模式 含义
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读写打开
O_EXEC 只执行打开
O_APPEND 每次写操作前都会将当期偏移量移动至文件尾部(原子操作),自行seek也没用
O_CLOEXEC FD_CLOEXEC写入文件描述符标志
O_CREAT 若文件不存在则创建,需要第三个参数perm值以确认文件权限
O_DIRECTORY 如果path不是目录的返回失败
O_EXCL 测试文件是否存在,与O_CREAT组合使用实现创建原子操作
O_LARGEFILE 支持大文件写入
O_NOFOLLOW 如果path是符号链接则出错
O_NONBLOCK 当path为FIFO、块特殊文件、字符特殊文件I/O操作为非阻塞
O_TRUNC 若文件存在,且可写,则长度截断为0
O_SYNC 每次write时等待物理I/O完成,包括本次write文件属性的更新更新
O_DSYNC 同SYNC但不需等待文件属性更新
O_RSYNC 使每个read此fd的操作的等待,直到所有对此文件挂起的write操作完成

支持打开模式:

模式 含义
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读写打开
O_EXEC 只执行打开
O_APPEND 每次写操作前都会将当期偏移量移动至文件尾部(原子操作),自行seek也没用
O_CLOEXEC FD_CLOEXEC写入文件描述符标志
O_CREAT 若文件不存在则创建,需要第三个参数perm值以确认文件权限
O_DIRECTORY 如果path不是目录的返回失败
O_EXCL 测试文件是否存在,与O_CREAT组合使用实现创建原子操作
O_LARGEFILE 支持大文件写入
O_NOFOLLOW 如果path是符号链接则出错
O_NONBLOCK 当path为FIFO、块特殊文件、字符特殊文件I/O操作为非阻塞
O_TRUNC 若文件存在,且可写,则长度截断为0
O_SYNC 每次write时等待物理I/O完成,包括本次write文件属性的更新更新
O_DSYNC 同SYNC但不需等待文件属性更新
O_RSYNC 使每个read此fd的操作的等待,直到所有对此文件挂起的write操作完成

3.创建文件creat

func Creat(path string, mode uint32) (fd int, err error)

等效调用
Open(path, O_CREAT|O_WRONLY|O_TRUNC, perm)
实践中可以使用
Open(path,O_RDWR|O_TRUNC|O_CREAT, perm)

4.关闭文件close

func Close(fd int) (err error)

进程终止时,内核自动关闭它打开的所有文件

5.调整偏移量lseek

func Seek(fd int, offset int64, whence int) (off int64, err error)

whence与offset关系有三种值:

  • whence=0 从文件开始处计算offset
  • whence=1 从文件当前位置处计算offset(可加可减)
  • whence=2 从文件结尾处计算offset

注意文件的偏移量可以调整至大于当前偏移量,当write后将在当前文件尾端和新开始写的位置间产生空洞,不会分配磁盘块

package main

import (
    "syscall"
    "os"
    "fmt"
)

func main() {
    b := []byte{'a','b','c'}
    fd, err := syscall.Open("/gocode/syscall/od.a", syscall.O_RDWR|syscall.O_CREAT|syscall.O_TRUNC, 0777)
    if err != nil {
        os.Exit(1)
    }
    offset, err := syscall.Seek(fd, 10000, 0)
    if err != nil {
        os.Exit(1)
    }
    fmt.Println("offset: ", offset)
    n, err := syscall.Write(fd, b)
    if err != nil {
        os.Exit(1)
    }
    fmt.Println("n: ", n)

}

od.a文件只分配了1个磁盘块


ls

6.读文件read

func Read(fd int, p []byte) (n int, err error)

返回成功读取的字符数量n, p为缓冲buffer

7.写文件write

func Write(fd int, p []byte) (n int, err error)

8.复制文件描述符 dup 、dup2

func Dup(oldfd int) (fd int, err error)
func Dup2(oldfd int, newfd int) (err error)
func Dup3(oldfd int, newfd int, flags int) (err error)

函数为原子操作
Dup复制文件描述符,返回一个当前可用最小的描述符
Dup2复制描述符至指定的描述符,若指定的描述符存在则先close再创建(会擦出掉文件描述符标志)
Dup3同Dup2但可以设置文件描述符标志O_CLOEXEC

dup

8.fcntl函数

golang暂不支持全部的fcntl仅支持文件锁相关函数,后续文章再详细讨论

9.sync、fsync、fdatasync

func Sync()
func Fsync(fd int) (err error)
func Fdatasync(fd int) (err error)
  • sync将修改过的块缓冲区排入写队列后立即返回
  • 通常操作系统会周期性(一般30s)的执行sync操作保证延迟写入的数据至磁盘
  • fsync确保指定的fd文件数据和属性立即写入磁盘,全部写入成功后返回
  • fdatasync确保指定fd文件的数据立即写入磁盘,全部写入成功后返回

10./dev/fd目录

该目录下保存一些文件描述符
可以通过open函数打开其中的描述符实现复制或创建新描述符,通常会忽略open中的模式设置,而是继承该描述符自由的模式

在linux中要格外注意,其/dev/fd的实现是把描述符映射成指向底层文件的符号链接,所以可以创建新模式,creat会对底层文件截断

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容

  • 1.文件描述符 所有执行I/O操作的系统调用都以文件描述符(一个非负整数)来指代打开的文件。文件描述符用以表示所有...
    666真666阅读 1,091评论 0 2
  • 1.1 C标准函数与系统函数 C标准是工作在操作系统之上的。比如要执行C标准函数printf函数,printf会调...
    FlyingReganMian阅读 989评论 0 0
  • 本文转载自实验楼:文件I/O(一) Linux系统调用 Linux系统调用(system call)是指操作系统提...
    mnikn阅读 282评论 0 0
  • 微风吹我,狂风袭我 温柔指尖拨过,激情指尖划过 我只发出美妙音乐 只因为美妙和谐才是我固有的频率。
    舒己怀_Frank阅读 242评论 20 32
  • 第二周调整计划如下: 每日完成打卡 1英语 单次60分钟 —— 完成5天 2打扫卫生或者3锻炼 选一,单次...
    星辰海绵oO阅读 196评论 0 0