os标准库

os包提供了操作系统函数,但和操作系统无关。

os包的接口规定为在所有操作系统中都是一致的。

设计为Unix风格的。

1. 权限说明

os标准库有大量的文件操作,在创建文件等操作中,需要指的perm。

在go语言中perm是一个uint32类型

在go语言中一般使用0777这样的形式进行表示。

  • 0代表是8进制

  • 777 是 - rwx rwx rwx的形式计算得出

权限项 文件类型 执行 执行 执行
字符表示 (d|l|c|s|p) r w x r w x r w x
数字表示 4 2 1 4 2 1 4 2 1
权限分配 文件所有者 文件所有者 文件所有者 文件所属组用户 文件所属组用户 文件所属组用户 其他用户 其他用户 其他用户

第一位:

- : 代表这是一个普通文件(regular)
d:目录文件(directory)
l : 链接文件(link)
b: 块设备文件(block)
c: 字符设备文件(character)
s : 套接字文件(socket)
p: 管道文件(pipe)

一共有三组rwx

  • 第一组:该文件拥有者的权限
  • 第二组:该文件拥有者所在组的其他成员对该文件的操作权限
  • 第三组:其他用户组的成员对该文件的操作权限

计算过程如下:

rwx rwx rwx
111 111 111
7 7 7

go中的FileMode定义

1
type FileMode uint32

FileMode代表文件的模式和权限位。这些字位在所有的操作系统都有相同的含义,因此文件的信息可以在不同的操作系统之间安全的移植。不是所有的位都能用于所有的系统,唯一共有的是用于表示目录的ModeDir位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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权限位(用于通过&获取类型位)
)

这些被定义的位是FileMode最重要的位。另外9个不重要的位为标准Unix rwxrwxrwx权限(任何人都可读、写、运行)。这些(重要)位的值应被视为公共API的一部分,可能会用于线路协议或硬盘标识:它们不能被修改,但可以添加新的位。

2. os.Create

1
func Create(name string) (file *File, err error)

Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件)。如果成功,返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。

如果出错,错误底层类型是*PathError

1
2
3
4
5
6
7
8
9
10
// 创建文件
func createFile() {
f, err := os.Create("test.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("f: %v\n", f)
}
}

3. os.Mkdir

创建单个目录

1
func Mkdir(name string, perm FileMode) error {}
1
2
3
4
5
6
7
func mkdir() {
err := os.Mkdir("ms", os.ModePerm)
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

4. os.MkdirAll

创建多级目录

1
func MkdirAll(path string, perm FileMode) error {}
1
2
3
4
5
6
7
func mkdirAll() {
err := os.MkdirAll("ms/one/two", os.ModePerm)
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

5. os.Remove

删除一个空的目录或一个文件

1
func Remove(name string) error {}
1
2
3
4
5
6
7
8
9
10
11
12
func removeFile() {
err := os.Remove("test.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}
func removeDir() {
err := os.Remove("ms/one/two")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

6. os.RemoveAll

强制删除目录以及目录汇中的文件

1
2
3
4
func RemoveAll(path string) error {
return removeAll(path)
}

1
2
3
4
5
6
7
func removeAllDir() {
err := os.RemoveAll("ms")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

7. os.Getwd

获得工作目录

1
func Getwd() (dir string, err error) {}
1
2
3
4
5
6
7
8
func getWd() {
dir, err := os.Getwd()
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("dir: %v\n", dir)
}
}

8. os.Chdir

修改工作目录

1
2
//改变工作目录到f,其中f必须为一个目录,否则便会报错
func (f *File) Chdir() error
1
2
3
4
5
6
7
8
func chDir() {
err := os.Chdir("d:/go/project")
if err != nil {
fmt.Printf("err: %v\n", err)
}
fmt.Println(os.Getwd())
}

9. os.TempDir

获得临时目录

1
2
3
func TempDir() string {
return tempDir()
}
1
2
3
4
func tempDir() {
s := os.TempDir()
fmt.Printf("s: %v\n", s)
}

10. os.Rename

重命名文件

1
2
3
func Rename(oldpath, newpath string) error {
return rename(oldpath, newpath)
}
1
2
3
4
5
6
7
8
9
10
11
12
func renameFile() {
err := os.Rename("test.txt", "test2.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}
func renameDir() {
err := os.Rename("ms", "ms1")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

11. os.Chmod

修改文件权限

1
2
3
func Chmod(name string, mode FileMode) error { 
return chmod(name, mode)
}
1
2
3
4
5
6
func chmod() {
err := os.Chmod("test2.txt", 0111)
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

打包linux测试

1
2
3
4
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build main.go

12. os.Chown

修改文件所有者

1
func Chown(name string, uid, gid int) error {}

cat /etc/passwd 查看uid和gid

1
2
3
4
5
6
func chown() {
err := os.Chown("test2.txt", 10, 10)
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

13. 文件

打开模式

1
2
3
4
5
6
7
8
9
10
11
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 // 如果可能,打开时清空文件
)

1
2
3
4
5
6
7
8
9
 // 创建一个空文件,注意当文件已经存在时,会直接覆盖掉原文件,不会报错
func Create(name string) (file *File, err error)
// 打开一个文件,注意打开的文件只能读,不能写
func Open(name string) (file *File, err error)
// 以指定的权限打开文件
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
// 关闭文件,关闭后不可读写
func (f *File) Close() error

其实os.Create 等价于:OpenFile(name, O_RDWF|O_CREATE|O_TRUNK, 0666)

1
2
3
4
5
6
7
8
9
func openClose() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
fmt.Println("file name : ", f.Name())
defer f.Close()

}

13.1 文件读取

1
2
3
4
5
6
7
8
9
10
11
// 获取文件的信息,里面有文件的名称,大小,修改时间等
func (f *File) Stat() (fi FileInfo, err error)
// 从文件中一次性读取b大小的数据,当读到文件结尾时,返回一个EOF错误
func (f *File) Read(b []byte) (n int, err error)
// 从文件中指定的位置(off)一次性读取b大小的数据
func (f *File) ReadAt(b []byte, off int64) (n int, err error)
// 读取目录并返回排好序的文件以及子目录名切片
func ReadDir(name string) ([]DirEntry, error)
//Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。
func (f *File) Seek(offset int64, whence int) (ret int64, err error)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type FileInfo interface {
Name() string // 文件的名字(不含扩展名)
Size() int64 // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同
Mode() FileMode // 文件的模式位
ModTime() time.Time // 文件的修改时间
IsDir() bool // 等价于Mode().IsDir()
Sys() interface{} // 底层数据来源(可以返回nil)
}

func fileStat() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
fileInfo, err := f.Stat()
if err != nil {
panic(err)
}
fmt.Printf("file info : %#v", fileInfo)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

func fileRead() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
var body []byte
for {
buf := make([]byte, 4)
n, err := f.Read(buf)
if err == io.EOF {
//读完了
break
}
fmt.Printf("读到的位置:%d \n", n)
body = append(body, buf[:n]...)
}
fmt.Printf("内容:%s \n", body)
}
1
2
3
4
5
6
7
8
9
10
11

func fileReadAt() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
buf := make([]byte, 5)
n, err := f.ReadAt(buf, 6)
fmt.Printf("内容:%s \n", buf[:n])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

func fileReadDir() {
f, err := os.Open("ms1")
if err != nil {
panic(err)
}
defer f.Close()
//-1代表所有
dirs, err := f.ReadDir(-1)
if err != nil {
panic(err)
}
for _, v := range dirs {
fmt.Println("is dir:", v.IsDir())
fmt.Println("dir name :", v.Name())
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13

func fileSeek() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
f.Seek(3, 0)
buf := make([]byte, 10)
n, _ := f.Read(buf)
fmt.Printf("读取内容:%s\n", buf[:n])
}

13.2 文件写

1
2
3
4
5
6
7
//Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
func (f *File) Write(b []byte) (n int, err error)
//WriteString类似Write,但接受一个字符串参数。
func (f *File) WriteString(s string) (ret int, err error)
//WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
func (f *File) WriteAt(b []byte, off int64) (n int, err error)

1
2
3
4
5
6
7
8
9
func fileWrite() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte("hello golang~\n"))
f.WriteString("hello golang~\n")
}
1
2
3
4
5
6
7
8
9
func fileWriteAt() {
f, err := os.OpenFile("test2.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
_, err = f.WriteAt([]byte(" insert content~\n"), 5)
fmt.Println(err)
}

14. 进程相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 让当前程序以给出的状态码(code)退出。一般来说,状态码0表示成功,非0表示出错。程序会立刻终止,defer的函数不会被执行。
func Exit(code int)
// 获取调用者的用户id
func Getuid() int
// 获取调用者的有效用户id
func Geteuid() int
// 获取调用者的组id
func Getgid() int
// 获取调用者的有效组id
func Getegid() int
// 获取调用者所在的所有组的组id
func Getgroups() ([]int, error)
// 获取调用者所在进程的进程id
func Getpid() int
// 获取调用者所在进程的父进程的进程id
func Getppid() int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

func osInfo() {
// 获得当前正在运行的进程id
fmt.Println("---------")
fmt.Printf("os.Getpid(): %v\n", os.Getpid())
// 父id
fmt.Printf("os.Getppid(): %v\n", os.Getppid())

// 设置新进程的属性
attr := &os.ProcAttr{
// files指定新进程继承的活动文件对象
// 前三个分别为,标准输入、标准输出、标准错误输出
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
// 新进程的环境变量
Env: os.Environ(),
}

// 开始一个新进程
p, err := os.StartProcess("c:\\windows\\system32\\notepad.exe", []string{"c:\\windows\\system32\\notepad.exe", "d:\\test.txt"}, attr)
if err != nil {
fmt.Println(err)
}
fmt.Println(p)
fmt.Println("进程ID:", p.Pid)

// 通过进程ID查找进程
p2, _ := os.FindProcess(p.Pid)
fmt.Println(p2)

// 等待10秒,执行函数
time.AfterFunc(time.Second*10, func() {
// 向p进程发出退出信号
p.Signal(os.Kill)
})

// 等待进程p的退出,返回进程状态
ps, _ := p.Wait()
fmt.Println(ps.String())
}

type Signal

1
2
3
4
type Signal interface {
String() string
Signal() // 用来区分其他实现了Stringer接口的类型
}

Signal代表一个操作系统信号。一般其底层实现是依赖于操作系统的:在Unix中,它是syscall.Signal类型。

1
2
3
4
var (
Interrupt Signal = syscall.SIGINT
Kill Signal = syscall.SIGKILL
)

仅有的肯定会被所有操作系统提供的信号,Interrupt(中断信号)和Kill(强制退出信号)。

1
2
3
4
5
6
var (
ErrInvalid = errors.New("invalid argument")
ErrPermission = errors.New("permission denied")
ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist")
)

一些可移植的、共有的系统调用错误。

1
2
3
4
5
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

Stdin、Stdout和Stderr是指向标准输入、标准输出、标准错误输出的文件描述符。

1
var Args []string

Args保管了命令行参数,第一个是程序名。

14.1 Signal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

func main() {
go a()
go b()
ch := make(chan os.Signal)
signal.Notify(ch, os.Kill, os.Interrupt)
c := <-ch
log.Println(c)
}

func b() {
fmt.Println("b")
}

func a() {
fmt.Println("a")
}

15. 环境相关

1
2
3
4
5
6
7
8
9
// 获取主机名
func Hostname() (name string, err error)
// 获取某个环境变量
func Getenv(key string) string
// 设置一个环境变量,失败返回错误,经测试当前设置的环境变量只在 当前进程有效(当前进程衍生的所有的go程都可以拿到,子go程与父go程的环境变量可以互相获取);进程退出消失
func Setenv(key, value string) error
// 删除当前程序已有的所有环境变量。不会影响当前电脑系统的环境变量,这些环境变量都是对当前go程序而言的
func Clearenv()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

func osEnv() {
// 获得所有环境变量
s := os.Environ()
fmt.Printf("s: %v\n", s)
// 获得某个环境变量
s2 := os.Getenv("GOPATH")
fmt.Printf("s2: %v\n", s2)
// 设置环境变量
os.Setenv("env1", "env1")
s2 = os.Getenv("aaa")
fmt.Printf("s2: %v\n", s2)
fmt.Println("--------------")

// 查找
s3, b := os.LookupEnv("env1")
fmt.Printf("b: %v\n", b)
fmt.Printf("s3: %v\n", s3)

// 清空环境变量
// os.Clearenv()
}