Go 学习笔记(44)— Go 标准库之 os(获取文件状态、获取/修改文件权限、创建、删除目录和文件、获取进程ID、设置获取环境变量)
1. 概述
os 包提供了操作系統函數的不依賴平臺的接口。失敗的調用會返回錯誤值而非錯誤碼。通常錯誤值里包含更多信息。例如,如果某個使用一個文件名的調用(如Open、Stat)失敗了,打印錯誤時會包含該文件名,錯誤類型將為 *PathError ,其內部可以解包獲得更多信息。
type PathError struct {Op stringPath stringErr error
}
PathError 記錄一個錯誤,以及導致錯誤的路徑。
func (e *PathError) Error() string
2. type FileInfo
type FileInfo interface {Name() string // 文件的名字(不含擴展名)Size() int64 // 普通文件返回值表示其大小;其他文件的返回值含義各系統不同Mode() FileMode // 文件的模式位ModTime() time.Time // 文件的修改時間IsDir() bool // 等價于Mode().IsDir()Sys() interface{} // 底層數據來源(可以返回nil)
}
FileInfo 用來描述一個文件對象。
func Stat(name string) (fi FileInfo, err error)
Stat 返回一個描述 name 指定的文件對象的 FileInfo 。如果指定的文件對象是一個符號鏈接,返回的 FileInfo 描述該符號鏈接指向的文件的信息,本函數會嘗試跳轉該鏈接。如果出錯,返回的錯誤值為 *PathError 類型。
代碼示例:
package mainimport ("fmt""os"
)func main() {// Stat 返回一個描述 name 指定的文件對象的 FileInfofi, err := os.Stat("./test.txt")if err != nil {fmt.Println(err)}fileName := fi.Name()fileSize := fi.Size()fileMode := fi.Mode()fileModTime := fi.ModTime()isDir := fi.IsDir()fileSys := fi.Sys()fmt.Printf("fileName is %#v\n", fileName)fmt.Printf("fileSize is %#v\n", fileSize)fmt.Printf("fileMode is %#v\n", fileMode)fmt.Printf("fileModTime is %#v\n", fileModTime)fmt.Printf("isDir is %#v\n", isDir)fmt.Printf("fileSys is %#v\n", fileSys)
}
3. type FileMode
FileModel 的方法主要用來進行判斷和輸出權限。
type FileMode uint32
FileMode 代表文件的模式和權限位。這些字位在所有的操作系統都有相同的含義,因此文件的信息可以在不同的操作系統之間安全的移植。不是所有的位都能用于所有的系統,唯一共有的是用于表示目錄的 ModeDir 位。
| 函數定義 | 函數說明 |
|---|---|
| func (m FileMode) IsDir() bool | IsDir報告m是否是一個目錄 |
| func (m FileMode) IsRegular() bool | IsRegular報告m是否是一個普通文件 |
| func (m FileMode) Perm() FileMode | Perm方法返回m的Unix權限位 |
| func (m FileMode) String() string | 返回m的字符串表示 |
使用示例:
func main() {// Stat 返回一個描述 name 指定的文件對象的 FileInfofi, err := os.Stat("./test.log")if err != nil {fmt.Println(err)}fm := fi.Mode() // 返回 FileMode fmt.Println(fm.IsDir()) // falsefmt.Println(fm.IsRegular()) // truefmt.Println(fm.Perm()) // -rw-rw----fmt.Println(fm.String()) // -rw-rw----
}
實際文件顯示:
wohu@wohu:~/GoCode/src/task$ ll
total 20
-rw-rw-r-- 1 wohu wohu 250 5月 20 09:40 main.go
-rw-rw---- 1 wohu wohu 0 5月 15 10:54 test.log
4. 主要函數
4.1 os.Hostname、Exit、Getpid、Getppid、
| 函數定義 | 函數說明 |
|---|---|
| func Hostname() (name string, err error) | Hostname返回內核提供的主機名。 |
| func Environ() []string | Environ返回表示環境變量的格式為"key=value"的字符串的切片拷貝 |
| func ExpandEnv(s string) string | 根據當前環境變量的值替換字符串中的 ${var} 或 $var。對未定義變量的引用將被空字符串替換 |
| func Getenv(key string) string | Getenv檢索并返回名為key的環境變量的值。如果不存在該環境變量會返回空字符串,要區分空值和未設置值,請使用 LookupEnv |
| func LookupEnv(key string) (string, bool) | 檢索 key 這個鍵對應的環境變量的值,如果該環境變量存在,則返回對應的值(可能為空),并且布爾值為 true,否則,返回值將為空,布爾值將為 false |
| func Setenv(key, value string) error | Setenv設置名為key的環境變量。如果出錯會返回該錯誤 |
| func Unsetenv(key string) error | 取消設置單個環境變量 |
| func Clearenv() | Clearenv刪除所有環境變量(謹慎使用) |
| func Exit(code int) | Exit讓當前程序以給出的狀態碼code退出。一般來說,狀態碼0表示成功,非0表示出錯。 程序會立刻終止,defer的函數不會被執行 |
| func Getuid() int | Getuid返回調用者的用戶ID |
| func Geteuid() int | Geteuid返回調用者的有效用戶ID |
| func Getgid() int | Getgid返回調用者的組ID |
| func Getegid() int | Getegid返回調用者的有效組ID |
| func Getgroups() ([]int, error) | Getgroups返回調用者所屬的所有用戶組的組ID |
| func Getpid() int | Getpid返回調用者所在進程的進程ID |
| func Getppid() int | Getppid返回調用者所在進程的父進程的進程ID |
使用示例:
func main() {hostname, err := os.Hostname()if err != nil {fmt.Println(err)}env := os.Environ()goroot := os.Getenv("GOROOT")name := os.Getenv("NAME")fmt.Println("name is:", name)pid := os.Getpid()ppid := os.Getppid()os.Exit(0)fmt.Println(hostname)fmt.Println(env)fmt.Println(goroot)fmt.Println(pid)fmt.Println(ppid)
}
執行:
$ NAME=wohu go run main.go
name is: wohu
示例
host := os.ExpandEnv("127.0.0.1:$PORT")
fmt.Println(host)
它會將 $PORT 替換為 os.Getenv("PORT") 的值。
4.2 os.IsExist
func IsExist(err error) bool
返回一個布爾值說明該錯誤是否表示一個文件或目錄已經存在。 ErrExist 和一些系統調用錯誤會使它返回真。
4.3 os.IsNotExist
func IsNotExist(err error) bool
返回一個布爾值說明該錯誤是否表示一個文件或目錄不存在。 ErrNotExist 和一些系統調用錯誤會使它返回真。
4.4 os.IsPermission
func IsPermission(err error) bool
返回一個布爾值說明該錯誤是否表示因權限不足要求被拒絕。 ErrPermission 和一些系統調用錯誤會使它返回真
4.5 os.Getwd
func Getwd() (dir string, err error)
返回一個對應當前工作目錄的根路徑。如果當前目錄可以經過多條路徑抵達(因為硬鏈接), Getwd 會返回其中一個。
4.5 os.Chdir
func Chdir(dir string) error
將當前工作目錄修改為 dir 指定的目錄。如果出錯,會返回 *PathError 底層類型的錯誤。
代碼示例如下:
func main() {_, err := os.Stat("./test.log")if os.IsExist(err) {fmt.Println("test.log do not exist")}if os.IsNotExist(err) {fmt.Println("test.log exist")}curDir, err := os.Getwd()if err != nil {fmt.Println(err)}fmt.Println(curDir) // /home/wohu/GoCode/src/taskerr = os.Chdir("/opt/")if err != nil {fmt.Println(err)}chDir, err := os.Getwd()if err != nil {fmt.Println(err)}fmt.Println(chDir) // opt
}
4.6 os.Chmod
func Chmod(name string, mode FileMode) error
修改 name 指定的文件對象的 mode 。如果 name 指定的文件是一個符號鏈接,它會修改該鏈接的目的地文件的 mode 。如果出錯,會返回 *PathError 底層類型的錯誤。
代碼示例:
func main() {// Stat 返回一個描述 name 指定的文件對象的 FileInfofi, err := os.Stat("./test.log")if err != nil {fmt.Println(err)}fm := fi.Mode() // 返回 FileModefilePerm := fm.Perm()fmt.Println(filePerm) // 修改前權限為 -rw-rw----err = os.Chmod("./test.log", 0755)if err != nil {fmt.Println(err)}fi, err = os.Stat("./test.log")if err != nil {fmt.Println(err)}filePerm = fm.Perm()fmt.Println(filePerm) // 修改后權限為 -rwxr-xr-x
}
4.7 os.Chown
func Chown(name string, uid, gid int) error
修改 name 指定的文件對象的用戶 id 和組 id 。如果 name 指定的文件是一個符號鏈接,它會修改該鏈接的目的地文件的用戶 id 和組 id 。如果出錯,會返回 *PathError 底層類型的錯誤。
4.8 os.Getgroups
func Getgroups() ([]int, error) 返回調用者屬于的 group ,其和 chown 配合使用,改變文件屬于的 group 。
代碼示例:
func main() {fmt.Println(os.Getgroups()) //獲取調用者屬于的組 [4 24 27 30 46 108 124 1000]fmt.Println(os.Getgid()) //獲取調用者當前所在的組 1000fmt.Println(os.Chown("tmp.txt", 1000, 46)) //更改文件所在的組
}
4.9 os.Mkdir
func Mkdir(name string, perm FileMode) error
使用指定的權限和名稱創建一個目錄,僅適用于創建父目錄存在且要創建的目錄不存在的情況。如果要創建的目錄已經存在,則會報錯,如果出錯,會返回 *PathError 底層類型的錯誤。
4.10 os.MkdirAll
func MkdirAll(path string, perm FileMode) error
使用指定的權限和名稱創建一個目錄,包括任何必要的上級目錄,并返回 nil ,否則返回錯誤。權限位 perm 會應用在每一個被本函數創建的目錄上。如果 path 指定了一個已經存在的目錄, MkdirAll 不做任何操作并返回 nil 。
代碼示例:
func main() {errMsg := os.Mkdir("./testDir", 0775)if errMsg != nil {fmt.Println("創建目錄失敗", errMsg)return}errMsg2 := os.MkdirAll("./a/b", 0775)if errMsg2 != nil {fmt.Println("創建目錄失敗", errMsg2)return}
}
4.11 os.Rename
func Rename(oldpath, newpath string) error
修改一個文件的名字,移動一個文件。可能會有一些個操作系統特定的限制。
4.12 os.Remove
func Remove(name string) error
刪除 name 指定的文件或目錄。如果是目錄的話必須要求該目錄為空才能刪除,否則會報錯,會返回 *PathError 底層類型的錯誤。
4.13 os.RemoveAll
func RemoveAll(path string) error
刪除 path 指定的文件,或目錄及它包含的任何下級對象。它會嘗試刪除所有東西,除非遇到錯誤并返回。如果 path 指定的對象不存在, RemoveAll 會返回 nil 而不返回錯誤。
示例代碼如下:
func main() {err := os.Rename("a", "b")if err != nil {fmt.Println(err)}err = os.Remove("./b")if err != nil {fmt.Println(err)}err = os.RemoveAll("./b")if err != nil {fmt.Println(err)}
}
5. type file
type File struct {// 內含隱藏或非導出字段
}
File 代表一個打開的文件對象。
5.1 返回文件對象的函數
5.1.1 os.Create
func Create(name string) (file *File, err error)
Create 采用模式 0666(任何人都可讀寫,不可執行)創建一個名為 name 的文件,如果文件已存在會截斷它(為空文件)。如果成功,返回的文件對象可用于 I/O ;對應的文件描述符具有 O_RDWR 模式。如果出錯,錯誤底層類型是 *PathError 。
5.1.2 os.Open
func Open(name string) (file *File, err error)
Open 打開一個文件用于讀取。如果操作成功,返回的文件對象的方法可用于讀取數據;對應的文件描述符具有 O_RDONLY 模式。如果出錯,錯誤底層類型是 *PathError 。
該函數只能以只讀模式打開文件。換句話說,我們只能從該函數返回的File值中讀取內容,而不能向它寫入任何內容。
5.1.3 os.OpenFile
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile 是一個更一般性的文件打開函數,大多數調用者都應用 Open 或 Create 代替本函數。它會使用指定的選項(如 O_RDONLY 等)、指定的模式(如 0666 等)打開指定名稱的文件。如果操作成功,返回的文件對象可用于 I/O 。如果出錯,錯誤底層類型是 *PathError 。
這個函數其實是 os.Create 函數和 os.Open 函數的底層支持,它最為靈活。這個函數有 3 個參數,分別名為 name、flag 和 perm 。其中的 name 指代的就是文件的路徑。而 flag 參數指的則是需要施加在文件描述符之上的模式,我在前面提到的只讀模式就是這里的一個可選項。在 Go 語言中,這個只讀模式由常量 os.O_RDONLY 代表,它是 int 類型的。當然了,這里除了只讀模式之外,還有幾個別的模式可選。
5.1.4 os.NewFile
func NewFile(fd uintptr, name string) *File
NewFile 使用給出的 Unix 文件描述符和名稱創建一個文件。該函數在被調用的時候,需要接受一個代表文件描述符的、uintptr 類型的值,以及一個用于表示文件名的字符串值。
注意,不要被這個函數的名稱誤導了,它的功能并不是創建一個新的文件,而是依據一個已經存在的文件的描述符,來新建一個包裝了該文件的 File 值。
eg:像這樣拿到一個包裝了標準錯誤輸出的 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")
}
圖片來源: https://time.geekbang.org/column/article/68779
5.2 文件對象的方法
func (f *File) Name() string
Name 方法返回(提供給 Open/Create 等方法的)文件名稱。
func (f *File) Stat() (fi FileInfo, err error)
Stat 返回描述文件 f 的 FileInfo 類型值。如果出錯,錯誤底層類型是 *PathError 。
func (f *File) Fd() uintptr
Fd 返回與文件 f 對應的整數類型的 Unix 文件描述符。
func (f *File) Chdir() error
Chdir 將當前工作目錄修改為 f , f 必須是一個目錄。如果出錯,錯誤底層類型是 *PathError 。
func (f *File) Chmod(mode FileMode) error
Chmod 修改文件的模式。如果出錯,錯誤底層類型是 *PathError 。
func (f *File) Chown(uid, gid int) error
Chown 修改文件的用戶 ID 和組 ID 。如果出錯,錯誤底層類型是 *PathError 。
func (f *File) Readdir(n int) (fi []FileInfo, err error)
Readdir 讀取目錄 f 的內容,返回一個有 n 個成員的 []FileInfo ,這些 FileInfo 是被 Lstat 返回的,采用目錄順序。對本函數的下一次調用會返回上一次調用剩余未讀取的內容的信息。
如果 n>0 , Readdir 函數會返回一個最多 n 個成員的切片。這時,如果 Readdir 返回一個空切片,它會返回一個非 nil 的錯誤說明原因。如果到達了目錄 f 的結尾,返回值 err 會是 io.EOF 。
如果 n<=0 , Readdir 函數返回目錄中剩余所有文件對象的 FileInfo 構成的切片。此時,如果 Readdir 調用成功(讀取所有內容直到結尾),它會返回該切片和 nil 的錯誤值。如果在到達結尾前遇到錯誤,會返回之前成功讀取的 FileInfo 構成的切片和該錯誤。
func (f *File) Readdirnames(n int) (names []string, err error)
Readdirnames 讀取并返回目錄 f 里面的文件的名字切片。
如果 n>0 , Readdirnames 返回最多 n 個名字。在這種情況下,如果 Readdirnames 返回一個空的切片,它會返回一個非空的錯誤來解釋原因。在目錄的結尾,錯誤為 EOF 。
如果 n<0 , Readdirnames 返回目錄下所有的文件的名字,用一個切片表示。在這種情況下,如果用一個切片表示成功(讀取直到目錄結尾),它返回切片和一個空的錯誤。如果在目錄結尾之前遇到了一個錯誤, Readdirnames 返回直到當前所讀到的 names 和一個非空的錯誤。
func (f *File) Truncate(size int64) error
Truncate 改變文件的大小,它不會改變 I/O 的當前位置。 如果截斷文件,多出的部分就會被丟棄。如果出錯,錯誤底層類型是 *PathError 。
func (f *File) Read(b []byte) (n int, err error)
Read 方法從 f 中讀取最多 len(b) 字節數據并寫入 b 。它返回讀取的字節數和可能遇到的任何錯誤。文件終止標志是讀取 0 個字節且返回值 err 為 io.EOF 。
func (f *File) ReadAt(b []byte, off int64) (n int, err error)
ReadAt 從指定的位置(相對于文件開始位置)讀取 len(b) 字節數據并寫入 b 。它返回讀取的字節數和可能遇到的任何錯誤。當 n<len(b) 時,本方法總是會返回錯誤;如果是因為到達文件結尾,返回值 err 會是 io.EOF 。
func (f *File) Write(b []byte) (n int, err error)
Write 向文件中寫入 len(b) 字節數據。它返回寫入的字節數和可能遇到的任何錯誤。如果返回值 n!=len(b) ,本方法會返回一個非 nil 的錯誤。
func (f *File) WriteString(s string) (ret int, err error)
WriteString 類似 Write ,但接受一個字符串參數。
func (f *File) WriteAt(b []byte, off int64) (n int, err error)
WriteAt 在指定的位置(相對于文件開始位置)寫入 len(b) 字節數據。它返回寫入的字節數和可能遇到的任何錯誤。如果返回值 n!=len(b) ,本方法會返回一個非 nil 的錯誤。
func (f *File) Seek(offset int64, whence int) (ret int64, err error)
Seek 設置下一次讀/寫的位置。
6. 用于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如果文件已存在,并且是常規的文件,那么就先清空其中已經存在的任何內容。
對于以上操作模式的使用,os.Create 函數和 os.Open 函數都是現成的例子。
func Create(name string) (*File, error) { return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
os.Create 函數在調用 os.OpenFile 函數的時候,給予的操作模式是 os.O_RDWR 、os.O_CREATE 和 os.O_TRUNC 的組合。
這就基本上決定了前者的行為,即:如果參數 name 代表路徑之上的文件不存在,那么就新建一個,否則,先清空現存文件中的全部內容。并且,它返回的 File 值的讀取方法和寫入方法都是可用的。
這里需要注意,多個操作模式是通過按位或操作符|組合起來的。
func Open(name string) (*File, error) {return OpenFile(name, O_RDONLY, 0)
}
os.Open 函數的功能是:以只讀模式打開已經存在的文件。其根源就是它在調用 os.OpenFile 函數的時候,只提供了一個單一的操作模式 os.O_RDONLY 。
7. 設定常規文件的訪問權限
我們已經知道,os.OpenFile 函數的第三個參數 perm 代表的是權限模式,其類型是 os.FileMode 。
但實際上,os.FileMode 類型能夠代表的,可遠不只權限模式,它還可以代表文件模式(也可以稱之為文件種類)。
由于 os.FileMode 是基于 uint32 類型的再定義類型,所以它的每個值都包含了 32 個比特位。在這 32 個比特位當中,每個比特位都有其特定的含義。
比如,如果在其最高比特位上的二進制數是1,那么該值表示的文件模式就等同于 os.ModeDir ,也就是說,相應的文件代表的是一個目錄。又比如,如果其中的第 26 個比特位上的是1,那么相應的值表示的文件模式就等同于 os.ModeNamedPipe ,也就是說,那個文件代表的是一個命名管道。
實際上,在一個 os.FileMode 類型的值(以下簡稱 FileMode 值)中,只有最低的 9 個比特位才用于表示文件的權限。當我們拿到一個此類型的值時,可以把它和 os.ModePerm 常量的值做按位與操作。這個常量的值是0777,是一個八進制的無符號整數,其最低的 9 個比特位上都是1,而更高的 23 個比特位上都是0。所以,經過這樣的按位與操作之后,我們即可得到這個 FileMode 值中所有用于表示文件權限的比特位,也就是該值所表示的權限模式。
這將會與我們調用 FileMode 值的 Perm 方法所得到的結果值是一致。在這 9 個用于表示文件權限的比特位中,每 3 個比特位為一組,共可分為 3 組。從高到低,這 3 組分別表示的是文件所有者(也就是創建這個文件的那個用戶)、文件所有者所屬的用戶組,以及其他用戶對該文件的訪問權限。而對于每個組,其中的 3 個比特位從高到低分別表示讀權限、寫權限和執行權限。如果在其中的某個比特位上的是1,那么就意味著相應的權限開啟,否則,就表示相應的權限關閉。
因此,八進制整數 0777 就表示:操作系統中的所有用戶都對當前的文件有讀、寫和執行的權限,而八進制整數 0666 則表示:所有用戶都對當前文件有讀和寫的權限,但都沒有執行的權限。我們在調用 os.OpenFile 函數的時候,可以根據以上說明設置它的第三個參數。
但要注意,只有在新建文件的時候,這里的第三個參數值才是有效的。在其他情況下,即使我們設置了此參數,也不會對目標文件產生任何的影響。
8. os 中關于進程的操作
參考:
https://studygolang.com/pkgdoc
https://www.cnblogs.com/sunailong/p/7554013.html
https://blog.csdn.net/weiyuefei/article/details/77892871
總結
以上是生活随笔為你收集整理的Go 学习笔记(44)— Go 标准库之 os(获取文件状态、获取/修改文件权限、创建、删除目录和文件、获取进程ID、设置获取环境变量)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 淘宝运费险多少钱啊?
- 下一篇: 双飞多少钱啊?