25-os

os包提供操控计算机操作系统的能力,都是与平台不相关的API。

平台不相关API:这些API基于(或者说抽象自)操作系统,为我们使用操作系统的功能提供高层次的支持,但是,它们并不依赖于具体的操作系统。

不论是什么操作系统,os包都提供统一的使用接口,使得我们可以用同样的方式,来操纵不同的操作系统,并得到相似的结果。其中的API帮助使用操作系统的:

  • 文件系统:操作文件系统的API最丰富

    os.File数据类型,代表了操作系统中的文件(对于Unix操作系统,万物皆文件),除了常见的文本文件、二进制文件、压缩文件、目录等,还有符号链接、各种物理设备(内置或外界的面向块或者字符的设备)、命名管道、套接字(socket)等。

  • 权限系统

  • 环境变量

  • 系统进程

  • 系统信号

os.File类型实现了哪些io包的接口

os.File类型拥有的都是指针方法,所以除了空接口,它本身没有任何接口,它的指针类型实现了很多io包中的接口。

*os.File类型实现了io.Readerio.Writerio.Closerio.ReadAtio.Seekerio.WriterAt。没有实现io.ByteReaderio.RuneReader

os.File类型以何种方式操作文件

获取os.File类型的指针值的方法,这些方法都执行同一个系统调用,并且在成功之后得到一个文件描述符,这个文件描述符会被存储在它们返回的File值中:

func Create(name string) (*File, error)
  • Create:根据给定的路径创建一个新的文件,返回一个File值和一个错误值(可能为非nil的错误值),对该函数返回的File值对应的文件进行读写操作。
    • 该函数创建的文件,对操作系统的所有用户都是可读写的
    • 如果函数的路径上已经存在了一个文件,那么会清空文件中全部的内容,然后把它作为第一个结果值返回
func NewFile(fd uintptr, name string) *File
  • NewFile:在被调用时,需要接受一个代表文件描述符的uintptr类型的值,以及一个用于表示文件名的字符串值

    • 如果给定的文件描述符并不有效,那么函数会返回nil
    • 否则返回一个代表文件的File值

    这个函数的功能并不是创建一个新的文件,而是依据已存在的文件的描述符,来创建一个包装了该文件的File值。如下所示,获取一个包装了标准错误输出的File值,然后通过这个File值向标准错误输出中写入一些内容:

    file3 := os.NewFile(uintptr(syscall.Stderr), "/dev/stderr")
    if file3 != nil {
        defer file3.Close()
        file3.WriteString("The Go language program writes the contents into stderr.\n")
    }
func Open(name string) (*File, error)
  • Open:打开一个文件,并返回包装了该文件的File值。该函数只能以只读模式打开文件,也就是只能读取文件内容,不能写入内容。如果调用这个File值的任何写入方法,都会得到“坏的文件描述符”的错误值。这个只读模式应用与File值所持有的文件描述符上。

    文件描述符,是又通常很小的非负整数代表的,它一般会由I/O相关的系统调用返回,并作为某个文件的一个标识存在。

    从操作系统层面看,针对任何文件的I/O操作都需要用到这个文件描述符。只不过Golang中的一些数据类型,我们隐藏掉了这个描述符,如此一来,就不需要时刻关注和辨别它,如os.File类型。

    os.File类型有一个指针方法,叫Fd,它在被调用之后将会返回一个uintptr类型的值,这个值代表了当前File值所持有的那个文件描述符。在os包中,只有NewFile函数需要用到它,它也没有别的用武之地,如果只是操作常规文件和目录,无需特别注意它。

func OpenFile(name string, flag int, perm FileMode) (*File, error)
  • OpenFile:这个函数是os.Createos.Open函数的底层支持,它最为灵活。

    这个函数的三个参数:

    • name:表示文件的路径
    • flag:需要施加在文件描述符之上的模式(如,只读模式os.O_RDONLY,它是int类型的),称为操作模式,限定操作文件的方式
    • perm:也是模式,它的类型是os.FileMode(此类型是一个基于unit32类型的再定义类型),称为权限模式,控制文件的访问权限

images

通过os.File类型的值,我们不但可以对文件进行读取、写入、关闭等操作,还可以设定下一次读取或写入是的起始索引位置。os包中:

  • 用于常见权限文件的Create函数
  • 用户包装现存文件的NewFile函数
  • 用以打开已存在的文件的Open函数和OpenFile函数

File的操作模式

针对File值的操作模式主要有:

  • 只读模式:os.O_RDONLY
  • 只写模式:os.O_WRONLY
  • 读写模式:os.O_RDWR

在我们新建或者打开一个文件的时候,必须把这三种模式中的一个设定为此文件的操作模式。

还可以为文件设置额外的操作模式:

  • os.O_APPEND:当向文件中写入内容时,把新内容追加到现有内容的后边
  • os.O_CREATE:当给定路径上的文件不存在时,创建一个新的文件
  • os.O_EXCL:需要与os.O_CREATE一同使用,表示在给定路径上不能有已存在的文件
  • os.O_SYNC:在打开的文件之上实施同步I/O,它会保证读写的内容总会与硬盘上的数据保持同步
  • os.O_TRUNC:如果文件已存在,并且是常规文件,那么就先情况其中已经存在的任何内容

例子

// Create函数
func Create(name string) (*File, error) {
 return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
//  给予的操作模式是 O_RDWR|O_CREATE|O_TRUNC的组合
// 如果参数name代表的路径之上的文件不存在那么就会新建一个
// 否则先情况现存文件中的全部内容
//  返回的File值的读方法和写方法都能可用
}


// Open函数
// 以只读模式打开已存在的文件
func open(name string)(*File, error){
    return OpenFile(name, O_REONLY, 0)
}

注意,多个操作模式通过桉位或操作符组合起来

File的权限模式

os.FileMode类型不但可以代表权限模式,还能代表文件模式(即,文件种类)。os.FileMode是基于uint32类型的在定义类型,所以它的每个值都包含了32个比特位,每个比特位都有特定的含义。

在一个os.FileMode类型值中,只有最低的9个比特位才用于表示文件权限(3个一组,共分为3组),当我们拿到一个此类型的值时,可以把它和os.ModePerm常量的值做按位与操作。这样就可以得到FileMode中所有用于表示文件权限的比特位,即权限模式。

例如,常量0777,是一个八进制无符号整数,它的最低9个比特位都是1,更高的23个比特位都是0.

  • 最高比特位为1,该值的文件模式等同于os.ModeDir,代表一个目录
  • 第26个比特位为1,告知的文件模式等同于os.ModeNamedPipe,代表一个命名管道

从高到底,这3组分别:

  • 表示文件所有者(创建文件的用户)
  • 文件所有者所属的用户组
  • 其他用户对该文件的访问权限

每组中的3个比特位从高到底分别表示:

  • 读权限
  • 写权限
  • 执行权限

如果在其中的某个比特位上的是1,就意味着相应的权限开启,否则,就标书相应的权限关闭。

在调用os.OpenFile函数的时候,可以根据上面的说明设置第三个参数,但是需要注意,只有在新建文件的时候,这里的第三个参数才是有效的,在其他情况下,即使设置了此参数,也不会对目标文件产生任何的影响。

上次修改: 25 November 2019