区块链开发之Go语言—文件系统
处理的文件名
- path库
- filepath库
查看文件的元信息
- os.Stat
- os.Lstat
操作临时文件区域
- os.TempDir
os — 平台无关的操作系统功能实现
os 封装了系统无关的实现。在实际编程中,我们应该总是优先使用 os 中提供的功能,而不是 syscall。
文件 I/O
了解IO需要参照Unix文件系统的概念。
- 在 Unix 系统调用中,所有执行 I/O 操作以文件描述符,一个非负整数(通常是小整数),来指代打开的文件。
- 文件描述符用以表示所有类型的已打开文件,包括管道(pipe)、FIFO、socket、终端、设备和普通文件。
- 在 Go 中,文件描述符封装在 os.File 结构中,通过 File.Fd() 可以获得底层的文件描述符:fd。
- 3 种标准的文件描述符:
- 0-标准输入;os.Stdin;对应Unix的/dev/stdin
- 1-标准输出;os.Stdout;对应Unix的/dev/stdout
- 2-标准错误;os.Stderr;对应Unix的/dev/stderr
打开一个文件:OpenFile
-
funcOpenFile(namestring,flagint,permFileMode)(*File,error)
- 参数 name 指定,它可以是绝对路径或相对路径(相对于进程当前工作目录),也可以是一个符号链接(会对其进行解引用)。
- 参数 flag 位掩码用于指定文件的访问模式,可用的值在 os 中定义为常量(以下值并非所有操作系统都可用)
const (
O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
O_RDWR int = syscall.O_RDWR // 读写模式打开文件
O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
O_CREATE int = syscall.O_CREAT // 如果不存在将创建一个新文件
O_EXCL int = syscall.O_EXCL // 和O_CREATE配合使用,文件必须不存在
O_SYNC int = syscall.O_SYNC // 打开文件用于同步I/O
O_TRUNC int = syscall.O_TRUNC // 如果可能,打开时清空文件
)
- 参数 perm 指定了文件的模式和权限位 //尴尬,这行排了好久排不好版,微信有bug。。
const (
// 单字符是被 String 方法用于格式化的属性缩写。
ModeDir FileMode = 1 << (32 - 1 - iota) // d: 目录
ModeAppend // a: 只能写入,且只能写入到末尾
ModeExclusive // l: 用于执行
ModeTemporary // T: 临时文件(非备份文件)
ModeSymlink // L: 符号链接(不是快捷方式文件)
ModeDevice // D: 设备
ModeNamedPipe // p: 命名管道(FIFO)
ModeSocket // S: Unix域socket
ModeSetuid // u: 表示文件具有其创建者用户id权限
ModeSetgid // g: 表示文件具有其创建者组id的权限
ModeCharDevice // c: 字符设备,需已设置ModeDevice
ModeSticky // t: 只有root/创建者能删除/移动文件
// 覆盖所有类型位(用于通过&获取类型位),对普通文件,所有这些位都不应被设置
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
ModePerm FileMode = 0777 // 覆盖所有Unix权限位(用于通过&获取类型位))
读取文件内容:Read和ReadAt
-
func(f*File)Read(b[]byte)(nint,err error)
Read 方法从 f 中读取最多 len(b) 字节数据并写入 b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值 err 为 io.EOF。 -
func(f*File)ReadAt(b[]byte,off int64)(nint,err error)
ReadAt 从指定的位置(相对于文件开始位置)读取长度为 len(b) 个字节数据并写入 b。它返回读取的字节数和可能遇到的任何错误。当 n<len(b) 时,本方法总是会返回错误;如果是因为到达文件结尾,返回值err="" 会是="" io.eof。<="" li="" style="box-sizing: border-box;"> - Read 和 ReadAt 的区别:前者从文件当前偏移量处读,且会改变文件当前的偏移量;而后者从 off 指定的位置开始读,且不会改变文件当前偏移量。
数据写入文件:Write
-
func(f*File)Write(b[]byte)(nint,err error)
Write 向文件中写入 len(b) 字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值 n!=len(b),本方法会返回一个非nil的错误。 - 注意:Write 调用成功并不能保证数据已经写入磁盘,因为内核会缓存磁盘的 I/O 操作。如果希望立刻将数据写入磁盘(一般场景不建议这么做,因为会影响性能),有两种办法:
- 打开文件时指定 os.O_SYNC;
- 调用 File.Sync() 方法。
关闭文件:Close
-
func(f*File)Close()error
os.File.Close() 是对 close() 的封装。我们应该养成关闭不需要的文件的良好编程习惯。文件描述符是资源,Go 的 gc 是针对内存的,并不会自动回收资源,如果关闭文件描述符,长期运行的服务可能会把文件描述符耗尽。 - 以下两种情况会导致 Close 返回错误:
- 关闭一个未打开的文件;
- 两次关闭同一个文件;
- 通常,我们不回去检查 Close 的错误。
改变文件偏移量:Seek
文件打开时,会将文件偏移量设置为指向文件开始,以后每次 Read 或 Write 调用将自动对其进行调整,以指向已读或已写数据后的下一个字节。因此,连续的 Read 和 Write 调用将按顺序递进,对文件进行操作。
-
func(f*File)Seek(offset int64,whenceint)(ret int64,err error)
Seek 可以调整文件偏移量- Seek 设置下一次读/写的位置。
- offset 为相对偏移量,
- whence 决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。使用中,whence 应该使用 os 包中的常量:SEEKSET、SEEKCUR 和 SEEK_END。
file.Seek(0,os.SEEK_SET)// 文件开始处 file.Seek(0, SEEK_END) // 文件结尾处的下一个字节 file.Seek(-1, SEEK_END) // 文件最后一个字节 file.Seek(-10, SEEK_CUR) // 当前位置前10个字节 file.Seek(1000, SEEK_END) // 文件结尾处的下1001个字节
- 注意:Seek 对应系统调用 lseek。该系统调用并不适用于所有类型,不允许将 lseek 应用于管道、FIFO、socket 或 终端。
截断文件
func Truncate(name string, size int64) error
func (f *File) Truncate(size int64) error
丢弃文件中大于size的后续字节。
文件属性
- 文件属性,也即文件元数据。
- 文件属性具体信息通过 os.FileInfo 接口获取。函数 Stat、Lstat 和 File.Stat 可以得到该接口的实例。
- stat 会返回所命名文件的相关信息。
- lstat 与 stat 类似,区别在于如果文件是符号链接,那么所返回的信息针对的是符号链接自身(而非符号链接所指向的文件)。
- fstat 则会返回由某个打开文件描述符(Go 中则是当前打开文件 File)所指代文件的相关信息。
改变文件时间戳
-
funcChtimes(namestring,atime time.Time,mtime time.Time)error
可以显示改变文件的访问时间和修改时间。
文件属主
每个文件都有一个与之关联的用户ID(UID)和组ID(GID),籍此可以判定文件的属主和属组。
func Chown(name string, uid, gid int) error
func Lchown(name string, uid, gid int) error
func (f *File) Chown(uid, gid int) error
文件权限
这里介绍是应用于文件和目录的权限方案,但其规则可适用于所有文件类型,包括设备文件、FIFO 以及 Unix 域套接字等。
普通文件的权限
- Owner(亦称为 user):授予文件属主的权限。
- Group:授予文件属组成员用户的权限。
- Other:授予其他用户的权限。 每一类用户授予的权限如下:
- Read:可阅读文件的内容。
- Write:可更改文件的内容。
- Execute:可以执行文件(如程序或脚本)
目录权限
- 读权限:可列出(比如,通过 ls 命令)目录之下的内容(即目录下的文件名)
- 写权限:可在目录内创建、删除文件。注意,要删除文件,对文件本身无需有任何权限。
- 可执行权限:可访问目录中的文件。因此,有时也将对目录的执行权限称为 search(搜索)权限。
Sticky 位
一般用于目录,起限制删除位的作用。可以在多用户环境下的共享文件夹里删除自己各自的文件。
- os.Chmod 和 os.File.Chmod 可以修改文件权限(包括 sticky 位),分别对应系统调用 chmod 和 fchmod。
目录与链接
创建和移除(硬)链接
硬链接是针对文件而言的,目录不允许创建硬链接。
funcLink(oldname,newnamestring)error
Link 创建一个名为 newname 指向 oldname 的硬链接。如果出错,会返回 *LinkError 类型的错误。
funcRemove(namestring)error
Remove 删除 name 指定的文件或目录。如果出错,会返回 *PathError 类型的错误。如果目录不为空,Remove 会返回失败。
更改文件名
funcRename(oldpath,newpathstring)error
Rename 修改一个文件的名字或移动一个文件。如果 newpath 已经存在,则替换它。注意,可能会有一些个操作系统特定的限制。
使用符号链接
funcSymlink(oldname,newnamestring)error
Symlink 创建一个名为 newname 指向 oldname 的符号链接。如果出错,会返回 *LinkError 类型的错误。
有时候,我们希望通过符号链接,能获取其所指向的路径名。系统调用 readlink 能做到,Go 的封装函数是 os.Readlink:
funcReadlink(namestring)(string,error)
创建和移除目录
-
funcMkdir(namestring,permFileMode)error
Mkdir 使用指定的权限和名称创建一个目录。如果出错,会返回 *PathError 类型的错误。 - 因为 Mkdir 所创建的只是路径名中的最后一部分,如果父目录不存在,创建会失败。os.MkdirAll 用于递归创建所有不存在的目录。
-
funcRemove(namestring)error
移除一个指定的目录,目录可以是绝对路径或相对路径。 -
funcRemoveAll(pathstring)error
RemoveAll 删除 path 指定的文件,或目录及它包含的任何下级对象。它会尝试删除所有东西,除非遇到错误并返回。如果 path 指定的对象不存在,RemoveAll 会返回 nil 而不返回错误。
读目录
func(f*File)Readdirnames(nint)(names[]string,err error)
Readdirnames 读取目录 f 的内容,返回一个最多有 n 个成员的[]string,切片成员为目录中文件对象的名字,采用目录顺序。对本函数的下一次调用会返回上一次调用未读取的内容的信息。
如果 n>0,Readdirnames 函数会返回一个最多 n 个成员的切片。这时,如果 Readdirnames 返回一个空切片,它会返回一个非 nil 的错误说明原因。如果到达了目录 f 的结尾,返回值 err 会是 io.EOF。
如果 n<=0,Readdirnames 函数返回目录中剩余所有文件对象的名字构成的切片。此时,如果 Readdirnames 调用成功(读取所有内容直到结尾),它会返回该切片和 nil 的错误值。如果在到达结尾前遇到错误,会返回之前成功读取的名字构成的切片和该错误。
-
func(f*File)Readdir(nint)(fi[]FileInfo,err error)
Readdir 内部会调用 Readdirnames,将得到的 names 构造路径,通过 Lstat 构造出 []FileInfo。
path/filepath — 兼容操作系统的文件路径操作
路径分隔符使用 os.PathSeparator
解析路径名字符串
func Dir(path string) string
func Base(path string) string
- Dir() 函数将一个路径名字符串分解成目录名。返回路径中除去最后一个路径元素的部分,即该路径最后一个元素所在的目录。在使用 Split 去掉最后一个元素后,会简化路径并去掉末尾的斜杠。如果路径是空字符串,会返回".";如果路径由1到多个斜杠后跟0到多个非斜杠字符组成,会返回"/";其他任何情况下都不会返回以斜杠结尾的路径。
- Base() 函数将一个路径名字符串分解成文件名。函数返回路径的最后一个元素。在提取元素前会去掉末尾的斜杠。如果路径是"",会返回".";如果路径是只有一个斜杆构成的,会返回"/"。
-
funcExt(pathstring)string
Ext 函数返回 path 文件扩展名。扩展名是路径中最后一个从 . 开始的部分,包括 .。如果该元素没有 . 会返回空字符串。
相对路径和绝对路径
-
funcIsAbs(pathstring)bool
返回路径是否是一个绝对路径 -
funcAbs(pathstring)(string,error)
Abs 函数返回 path 代表的绝对路径,如果 path 不是绝对路径,会加入当前工作目录以使之成为绝对路径。 -
funcRel(basepath,targpathstring)(string,error)
Rel 函数返回一个相对路径
fmt.Println(filepath.Rel("/home/polaris/studygolang", "/home/polaris/studygolang/src/logic/topic.go"))
fmt.Println(filepath.Rel("/home/polaris/studygolang", "/data/studygolang"))
// Output:
// src/logic/topic.go <nil>
// ../../../data/studygolang <nil>
路径的切分和拼接
-
funcSplit(pathstring)(dir,filestring)
Split 函数根据最后一个路径分隔符将路径 path 分隔为目录和文件名两部分(dir 和 file) -
funcJoin(elem...string)string
Join 用于将多个路径拼接起来,会根据情况添加路径分隔符。 -
funcSplitList(pathstring)[]string
SplitList 分割 PATH 或 GOPATH 之类的环境变量(这些路径被特定于OS 的列表分隔符连接起来)
规整化路径
-
funcClean(pathstring)string
通过单纯的词法操作返回和 path 代表同一地址的最短路径。
符号链接指向的路径名
-
funcEvalSymlinks(pathstring)(string,error)
path 或返回值是相对路径,则是相对于进程当前工作目录。
文件路径匹配
-
funcGlob(patternstring)(matches[]string,err error)
Glob 函数返回所有匹配了 模式字符串 pattern 的文件列表或者nil(如果没有匹配的文件)。Glob 的常见用法,是读取某个目录下所有的文件,比如写单元测试时,读取 testdata 目录下所有测试数据:filepath.Glob("testdata/*.input")
遍历目录
-
funcWalk(rootstring,walkFnWalkFunc)error
Walk 函数会遍历 root 指定的目录下的文件树,对每一个该文件树中的目录和文件都会调用 walkFn,包括 root 自身。所有访问文件/目录时遇到的错误都会传递给 walkFn 过滤。文件是按字典顺序遍历的,这让输出更漂亮,但也导致处理非常大的目录时效率会降低。Walk 函数不会遍历文件树中的符号链接(快捷方式)文件包含的路径。 -
typeWalkFuncfunc(pathstring,info os.FileInfo,err error)error
Walk 函数对每一个文件/目录都会调用 WalkFunc 函数类型值。调用时 path 参数会包含 Walk 的 root 参数作为前缀;就是说,如果 Walk 函数的 root 为 "dir",该目录下有文件 "a",将会使用 "dir/a" 作为调用 walkFn 的参数。walkFn 参数被调用时的 info 参数是 path 指定的地址(文件/目录)的文件信息,类型为 os.FileInfo。
参考
1.[《Go语言标准库》The Golang Standard Library by Example]( https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter01/01.0.html)
- 使用MagicAjax 实现无刷新Webparts
- Python 项目实践一(外星人入侵小游戏)第五篇
- Python 项目实践一(外星人入侵小游戏)第三篇
- WordPress自定义栏目运用实例 VI:设置外链缩略图/特色图像
- Python 项目实践一(外星人入侵小游戏)第二篇
- IBatisNet配置
- WordPress设置评论到达一定数量后自动关闭评论功能
- Python 项目实践一(外星人入侵)第一篇
- 外媒:域名Covermate.com超35万终端交易
- 移除WordPress 管理后台的主题编辑功能
- 百度区域链开放平台“BaaS”启用了二级子域名chain.baidu.com
- Qt界面UI之QML初见(学习笔记四)
- 清新唯美的jQuery天气预报插件(网页天气预报插件)
- 32和64位的CentOS 6.0下 安装 Mono 2.10.8 和Jexus 5.0
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- AkShare-股票数据-龙虎榜-机构席位追踪
- AkShare-股票数据-龙虎榜-营业上榜统计
- AkShare-股票数据-龙虎榜-个股上榜统计
- React中路由的使用
- CyanX 基于ReactHook的状态管理器,遵循函数式编程的理念,极简、可扩展设计哲学上手
- Serverless 架构下如何实现日志的实时输出?
- typescript基础篇(1):helloworld
- typescript基础篇(2):数据类型
- 22款好用的CLI工具
- typescript基础篇(3):接口
- 2020 年,苹果的 AI 还有创新吗?
- 毕设有着落了!一套开源的,基于SpringBoot的车牌识别系统
- 详解hive的join优化
- 区块链时代的世界宪章:代码即法律
- SQL 计算公司的期初资产