os包中實現了平臺無關的接口,設計向Unix風格,但是錯誤處理是go風格,當os包使用時,如果失敗之後返回錯誤類型而不是錯誤數量.
os包中函數設計方式和Unix類似,下面來看一下.
func Chdir(dir string) error //chdir將當前工作目錄更改爲dir目錄.
func Getwd() (dir string, err error) //獲取當前目錄,類似linux中的pwd
func Chmod(name string, mode FileMode) error //更改文件的權限(讀寫執行,分爲三類:all-group-owner)
func Chown(name string, uid, gid int) error //更改文件擁有者owner
func Chtimes(name string, atime time.Time, mtime time.Time) error //更改文件的訪問時間和修改時間,atime表示訪問時間,mtime表示更改時間
func Clearenv() //清除所有環境變量(慎用)
func Environ() []string //返回所有環境變量
func Exit(code int) //系統退出,並返回code,其中0表示執行成功並退出,非0表示錯誤並退出,其中執行Exit後程序會直接退出,defer函數不會執行.
func Expand(s string, mapping func(string) string) string //Expand用mapping 函數指定的規則替換字符串中的${var}或者$var(注:變量之前必須有$符號)。比如,os.ExpandEnv(s)等效於os.Expand(s, os.Getenv)。
package main
import (
"fmt"
"os"
)
func main() {
mapping := func(key string) string {
m := make(map[string]string)
m = map[string]string{
"world": "kitty",
"hello": "hi",
}
if m[key] != "" {
return m[key]
}
return key
}
s := "hello,world" // hello,world,由於hello world之前沒有$符號,則無法利用map規則進行轉換
s1 := "$hello,$world $finish" // hi,kitty finish,finish沒有在map規則中,所以還是返回原來的值
fmt.Println(os.Expand(s, mapping))
fmt.Println(os.Expand(s1, mapping))
}
func ExpandEnv(s string) string //ExpandEnv根據當前環境變量的值來替換字符串中的${var}或者$var。如果引用變量沒有定義,則用空字符串替換。
func main() {
s := "hello $GOROOT"
fmt.Println(os.ExpandEnv(s)) // hello /home/work/software/go,$GOROOT替換爲環境變量的值,而h沒有環境變量可以替換,返回空字符串
}
func Getenv(key string) string //獲取系統key的環境變量,如果沒有環境變量就返回空
fmt.Println(os.Getenv("GOROOT")) // /home/software/go
func Geteuid() int //獲取調用者用戶id
func Getgid() int //獲取調用者的組id
fmt.Println(os.Getgid()) // 1000
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()) //獲取調用者當前所在的組 1000
fmt.Println(os.Chown("tmp.txt", 1000, 46)) //更改文件所在的組
}
func Getpagesize() int //獲取底層系統內存頁的數量
func Getpid() int //獲取進程id
func Getppid() int //獲取調用者進程父id
func Hostname() (name string, err error) //獲取主機名
func IsExist(err error) bool //返回一個布爾值,它指明
err
錯誤是否報告了一個文件或者目錄已經存在。它被ErrExist和其它系統調用滿足。func IsNotExist(err error) bool //返回一個布爾值,它指明
err
錯誤是否報告了一個文件或者目錄不存在。它被ErrNotExist 和其它系統調用滿足。func IsPathSeparator(c uint8) bool //判斷c是否是一個路徑分割符號,是的話返回true,否則返回false
fmt.Println(os.IsPathSeparator('/')) //true
fmt.Println(os.IsPathSeparator('|')) //false
func IsPermission(err error) bool //判定
err
錯誤是否是權限錯誤。它被ErrPermission 和其它系統調用滿足。func Lchown(name string, uid, gid int) error //改變了文件的
gid
和uid
。如果文件是一個符號鏈接,它改變的鏈接自己。如果出錯,則會是*PathError類型。func Link(oldname, newname string) error //創建一個從oldname指向newname的硬連接,對一個進行操作,則另外一個也會被修改.
func Mkdir(name string, perm FileMode) error //創建一個新目錄,該目錄具有FileMode權限,當創建一個已經存在的目錄時會報錯
func main() {
var path string
if os.IsPathSeparator('\\') {
path = "\\"
} else {
path = "/"
}
pwd, _ := os.Getwd()
err := os.Mkdir(pwd+path+"tmp", os.ModePerm)
if err != nil {
fmt.Println(err)
}
}
func MkdirAll(path string, perm FileMode) error //創建一個新目錄,該目錄是利用路徑(包括絕對路徑和相對路徑)進行創建的,如果需要創建對應的父目錄,也一起進行創建,如果已經有了該目錄,則不進行新的創建,當創建一個已經存在的目錄時,不會報錯.
func NewSyscallError(syscall string, err error) error //NewSyscallError返回一個SyscallError 錯誤,帶有給出的系統調用名字和詳細的錯誤信息。也就是說,如果err爲空,則返回空
func main() {
a := os.NewSyscallError("mkdir", nil)
fmt.Println(a) // nil
a = os.NewSyscallError("mkdir", errors.New("bad error"))
fmt.Println(a) //mkdir: bad error
}
func Readlink(name string) (string, error) //返回符號鏈接的目標。如果出錯,將會是 *PathError類型。
func Remove(name string) error //刪除文件或者目錄
func RemoveAll(path string) error //刪除目錄以及其子目錄和文件,如果path不存在的話,返回nil
func main() {
err := os.MkdirAll("./a", os.ModePerm)
os.Chdir("./a")
os.Create("file.txt")
fmt.Println(err)//成功創建文件file.txt,返回nil
os.Chdir("../")
err = os.RemoveAll("./a")
fmt.Println(err)//成功刪除目錄a,返回nil
}
func Rename(oldpath, newpath string) error //重命名文件,如果oldpath不存在,則報錯no such file or directory
func SameFile(fi1, fi2 FileInfo) bool //查看f1和f2這兩個是否是同一個文件,如果再Unix系統,這意味着底層結構的device和inode完全一致,在其他系統上可能是基於文件絕對路徑的.SameFile只適用於本文件包stat返回的狀態,其他情況下都返回false
func Setenv(key, value string) error //設定環境變量,經常與Getenv連用,用來設定環境變量的值
func main() {
err := os.Setenv("goenv", "go environment")
a := os.Getenv("goenv")
fmt.Println(err, a) // <nil> go environment
}
func Symlink(oldname, newname string) error //創建一個newname作爲oldname的符號連接,這是一個符號連接(Link是硬連接),與link的硬連接不同,利用Link創建的硬連接,則newname和oldname的file互不影響,一個文件刪除,另外一個文件不受影響;但是利用SymLink創建的符號連接,其newname只是一個指向oldname文件的符號連接,當oldname file刪除之後,則newname的文件也就不能夠繼續使用.
func TempDir() string //創建臨時目錄用來存放臨時文件,這個臨時目錄一般爲/tmp
func Truncate(name string, size int64) error //按照指定長度size將文件截斷,如果這個文件是一個符號鏈接,則同時也改變其目標連接的長度,如果有錯誤,則返回一個錯誤.
文件操作:
type File
type File struct {
// contains filtered or unexported fields
}
File表示打開的文件描述符
func Create(name string) (file *File, err error) //創建一個文件,文件mode是0666(讀寫權限),如果文件已經存在,則重新創建一個,原文件被覆蓋,創建的新文件具有讀寫權限,能夠備用與i/o操作.其相當於OpenFile的快捷操作,等同於OpenFile(name string, O_CREATE,0666)
func NewFile(fd uintptr, name string) *File //根據文件描述符和名字創建一個新的文件
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
func Open(name string) (file *File, err error) //打開一個文件,返回文件描述符,該文件描述符只有只讀權限.他相當於OpenFile(name string,O_RDWR,0)
func OpenFile(name string, flag int, perm FileMode) (file *File, err error) //指定文件權限和打開方式打開name文件或者create文件,其中flag標誌如下:
打開標記:
O_RDONLY:只讀模式(read-only)O_WRONLY:只寫模式(write-only)
O_RDWR:讀寫模式(read-write)
O_APPEND:追加模式(append)
O_CREATE:文件不存在就創建(create a new file if none exists.)
O_EXCL:與 O_CREATE 一起用,構成一個新建文件的功能,它要求文件必須不存在(used with O_CREATE, file must not exist)
O_SYNC:同步方式打開,即不使用緩存,直接寫入硬盤
O_TRUNC:打開並清空文件
至於操作權限perm,除非創建文件時才需要指定,不需要創建新文件時可以將其設定爲0.雖然go語言給perm權限設定了很多的常量,但是習慣上也可以直接使用數字,如0666(具體含義和Unix系統的一致).
func Pipe() (r *File, w *File, err error) //返回一對連接的文件,從r中讀取寫入w中的數據,即首先向w中寫入數據,此時從r中變能夠讀取到寫入w中的數據,Pipe()函數返回文件和該過程中產生的錯誤.
func main() {
r, w, _ := os.Pipe()
w.WriteString("hello,world!")
var s = make([]byte, 20)
n, _ := r.Read(s)
fmt.Println(string(s[:n])) // hello,world!
}
func (f *File) Chdir() error //改變工作目錄到f,其中f必須爲一個目錄,否則便會報錯
func main() {
dir, _ := os.Getwd()
fmt.Println(dir)
f, _ := os.Open("tmp.txt")
err := f.Chdir()
if err != nil {
fmt.Println(err) //chdir tmp.txt: not a directory,因爲tmp.txt不是目錄,所以報錯
}
f, _ = os.Open("develop")
err = f.Chdir()
if err != nil {
fmt.Println(err)
}
dir1, _ := os.Getwd()
fmt.Println(dir1) //home/work/develop,因爲develop是工作目錄,所以變切換到該目錄
}
func (f *File) Chmod(mode FileMode) error //更改文件權限,其等價與os.Chmod(name string,mode FileMode)error
func (f *File) Chown(uid, gid int) error //更改文件所有者,與os.Chown等價
func (f *File) Close() error //關閉文件,使其不能夠再進行i/o操作,其經常和defer一起使用,用在創建或者打開某個文件之後,這樣在程序退出前變能夠自己關閉響應的已經打開的文件.
func (f *File) Fd() uintptr //返回系統文件描述符,也叫做文件句柄.
func (f *File) Name() string //返回文件名字,與file.Stat().Name()等價
func (f *File) Read(b []byte) (n int, err error) //將len(b)的數據從f中讀取到b中,如果無錯,則返回n和nil,否則返回讀取的字節數n以及響應的錯誤
func (f *File) ReadAt(b []byte, off int64) (n int, err error) //和Read類似,不過ReadAt指定開始讀取的位置offset
func (f *File) Readdir(n int) (fi []FileInfo, err error)
Readdir讀取file指定的目錄的內容,然後返回一個切片,它最多包含n
個FileInfo值,這些值可能是按照目錄順序的Lstat返回的。接下來調用相同的文件會產生更多的FileInfos。
如果n>0,Readdir返回最多n
個FileInfo結構。在這種情況下,如果Readdir返回一個空的切片,它將會返回一個非空的錯誤來解釋原因。在目錄的結尾,錯誤將會是io.EOF。
如果n<=0,Readdir返回目錄的所有的FileInfo,用一個切片表示。在這種情況下,如果Readdir成功(讀取直到目錄的結尾),它會返回切片和一個空的錯誤。如果它在目錄的結尾前遇到了一個錯誤,Readdir返回直到當前所讀到的FIleInfo和一個非空的錯誤。
func (f *File) Readdirnames(n int) (names []string, err error)
Readdirnames讀取並返回目錄f
裏面的文件的名字切片。
如果n>0,Readdirnames返回最多n個名字。在這種情況下,如果Readdirnames返回一個空的切片,它會返回一個非空的錯誤來解釋原因。在目錄的結尾,錯誤爲EOF。
如果n<0,Readdirnames返回目錄下所有的文件的名字,用一個切片表示。在這種情況下,如果用一個切片表示成功(讀取直到目錄結尾),它返回切片和一個空的錯誤。如果在目錄結尾之前遇到了一個錯誤,Readdirnames返回直到當前所讀到的names
和一個非空的錯誤。
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("/home/chenbaoke")
if err != nil {
fmt.Println(err)
}
fileslice, err := file.Readdir(5)
if err != nil {
fmt.Println(err)
}
for _, f := range fileslice {
fmt.Println(f.Name()) //輸出5個文件的名字
}
filename, err := file.Readdirnames(-1)
if err != nil {
fmt.Println(err)
}
for _, f := range filename {
fmt.Println(f) //輸出所有文件的名字
}
}
func (f *File) Seek(offset int64, whence int) (ret int64, err error) //Seek設置下一次讀或寫操作的偏移量
offset
,根據whence
來解析:0意味着相對於文件的原始位置,1意味着相對於當前偏移量,2意味着相對於文件結尾。它返回新的偏移量和錯誤(如果存在)。
func main() {
s := make([]byte, 10)
file, _ := os.Open("tmp.txt")
defer file.Close()
file.Seek(-12, 2) // 從離最後位置12的地方開始
n, _ := file.Read(s)
fmt.Println(string(s[:n]))
}
func (f *File) Stat() (fi FileInfo, err error) //返回文件描述相關信息,包括大小,名字等.等價於os.Stat(filename string)
func (f *File) Sync() (err error) //同步操作,將當前存在內存中的文件內容寫入硬盤.
func (f *File) Truncate(size int64) error //類似 os.Truncate(name, size),,將文件進行截斷
func (f *File) Write(b []byte) (n int, err error) //將b中的數據寫入f文件
func (f *File) WriteAt(b []byte, off int64) (n int, err error) //將b中數據寫入f文件中,寫入時從offset位置開始進行寫入操作
func (f *File) WriteString(s string) (ret int, err error) //將字符串s寫入文件中
func main() {
file, _ := os.Create("tmp.txt")
a := "hellobyte"
file.WriteAt([]byte(a), 10) //在文件file偏移量10處開始寫入hellobyte
file.WriteString("string") //在文件file偏移量0處開始寫入string
file.Write([]byte(a)) //在文件file偏移量string之後開始寫入hellobyte,這個時候就會把開始利用WriteAt在offset爲10處開始寫入的hellobyte進行部分覆蓋
b := make([]byte, 20)
file.Seek(0, 0) //file指針指向文件開始位置
n, _ := file.Read(b)
fmt.Println(string(b[:n])) //stringhellobytebyte,這是由於在寫入過程中存在覆蓋造成的
}
type FileInfo
type FileInfo interface {
Name() string //文件名字
Size() int64 // length in bytes for regular files; system-dependent for others,文件大小
Mode() FileMode // file mode bits,文件權限
ModTime() time.Time // modification time 文件更改時間
IsDir() bool // abbreviation for Mode().IsDir() 文件是否爲目錄
Sys() interface{} // underlying data source (can return nil) 基礎數據源
}
FileInfo經常被Stat和Lstat返回來描述一個文件
func Lstat(name string) (fi FileInfo, err error) //返回描述文件的FileInfo信息。如果文件是符號鏈接,返回的FileInfo描述的符號鏈接。Lstat不會試着去追溯link。如果出錯,將是 *PathError類型。
func Stat(name string) (fi FileInfo, err error) //返回描述文件的FileInfo信息。如果出錯,將是 *PathError類型。
type FileMode
type FileMode uint32
FileMode代表文件的模式和權限標誌位。標誌位在所有的操作系統有相同的定義,因此文件的信息可以從一個操作系統移動到另外一個操作系統。不是所有的標誌位是用所有的系統。唯一要求的標誌位是目錄的ModeDir。
const (
// The single letters are the abbreviations
// used by the String method's formatting.
ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
ModeAppend // a: append-only
ModeExclusive // l: exclusive use
ModeTemporary // T: temporary file (not backed up)
ModeSymlink // L: symbolic link
ModeDevice // D: device file
ModeNamedPipe // p: named pipe (FIFO)
ModeSocket // S: Unix domain socket
ModeSetuid // u: setuid
ModeSetgid // g: setgid
ModeCharDevice // c: Unix character device, when ModeDevice is set
ModeSticky // t: sticky
// Mask for the type bits. For regular files, none will be set.
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
ModePerm FileMode = 0777 // permission bits
)
所定義的文件標誌位最重要的位是FileMode。9個次重要的位是標準Unix rwxrwxrwx權限。這些位的值應該被認爲公開API的一部分,可能用於連接協議或磁盤表示:它們必須不能被改變,儘管新的標誌位有可能增加。
FileModel的方法主要用來進行判斷和輸出權限
func (m FileMode) IsDir() bool //判斷m是否是目錄,也就是檢查文件是否有設置的ModeDir位
func (m FileMode) IsRegular() bool //判斷m是否是普通文件,也就是說檢查m中是否有設置mode type
func (m FileMode) Perm() FileMode //返回m的權限位
func (m FileMode) String() string //返回m的字符串表示
func main() {
fd, err := os.Stat("tmp.txt")
if err != nil {
fmt.Println(err)
}
fm := fd.Mode()
fmt.Println(fm.IsDir()) //false
fmt.Println(fm.IsRegular()) //true
fmt.Println(fm.Perm()) //-rwxrwxrwx
fmt.Println(fm.String()) //-rwxrwxrwx
}
type LinkError
type LinkError struct { Op string Old string New string Err error }
func (e *LinkError) Error() string //LinkError記錄了一個在鏈接或者符號連接或者重命名的系統調用中發生的錯誤和引起錯誤的文件的路徑。
type PathError
type PathError struct {
Op string
Path string
Err error
}
func (e *PathError) Error() string //返回一個有操作者,路徑以及錯誤組成的字符串形式
進程相關操作:
type ProcAttr
type ProcAttr struct {
Dir string //如果dir不是空,子進程在創建之前先進入該目錄
Env []string //如果Env不是空,則將裏面的內容賦值給新進程的環境變量,如果他爲空,則使用默認的環境變量
Files []*File //Files指定新進程打開文件,前三個實體分別爲標準輸入,標準輸出和標準錯誤輸出,可以添加額外的實體,這取決於底層的操作系統,當進程開始時,文
//件對應的空實體將被關閉
Sys *syscall.SysProcAttr //操作系統特定進程的屬性,設置該值也許會導致你的程序在某些操作系統上無法運行或者編譯
}
ProcAttr包含屬性,這些屬性將會被應用在被StartProcess啓動的新進程上type Process Process存儲了通過StartProcess創建的進程信息。
type Process struct {
Pid int
handle uintptr //處理指針
isdone uint32 // 如果進程正在等待則該值非0,沒有等待該值爲0
}
func FindProcess(pid int) (p *Process, err error) //通過進程pid查找運行的進程,返回相關進程信息及在該過程中遇到的errorfunc StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) //StartProcess啓動一個新的進程,其傳入的name
、argv
和addr
指定了程序、參數和屬性;StartProcess是一個低層次的接口。os/exec包提供了高層次的接口;如果出錯,將會是*PathError錯誤。func
(p *Process) Kill() error //殺死進程並直接退出func (p *Process) Release() error //釋放進程p的所有資源,之後進程p便不能夠再被使用,只有Wati沒有被調用時,才需要調用Release釋放資源
func main() {
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, //其他變量如果不清楚可以不設定
}
p, err := os.StartProcess("/usr/bin/vim", []string{"/usr/bin/vim", "tmp.txt"}, attr) //vim 打開tmp.txt文件
if err != nil {
fmt.Println(err)
}
fmt.Println(p) //&{5488 240 0}
pro, _ := os.FindProcess(p.Pid) //查找進程
fmt.Println(pro) //&{5488 240 0}
err = p.Kill() //殺死進程但不釋放進程相關資源
fmt.Println(err)
err = p.Release() //<span style="color:#FF0000;">釋放進程相關資源,因爲資源釋放凋之後進程p就不能進行任何操作,此後進程P的任何操作都會被報錯</span>
fmt.Println(err)
}
func (p *Process) Signal(sig Signal) error //發送一個信號給進程p, 在windows中沒有實現發送中斷interrupt
func (p *Process) Wait() (*ProcessState, error) //Wait等待進程退出,並返回進程狀態和錯誤。Wait釋放進程相關的資源。在大多數的系統上,進程p必須是當前進程的子進程,否則會返回一個錯誤。
func main() {
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, //其他變量如果不清楚可以不設定
}
p, err := os.StartProcess("/usr/bin/vim", []string{"/usr/bin/vim", "tmp.txt"}, attr) //vim 打開tmp.txt文件
if err != nil {
fmt.Println(err)
}
go func() {
p.Signal(os.Kill) //kill process
}()
pstat, err := p.Wait()
if err != nil {
fmt.Println(err)
}
fmt.Println(pstat) //signal: killed
}
type ProcessState //ProcessState存儲了Wait函數報告的進程信息
type ProcessState struct {
pid int
status syscall.WaitStatus
rusage *syscall.Rusage
}
func (p *ProcessState) Exited() bool // 判斷程序是否已經退出
func (p *ProcessState) Pid() int //返回退出進程的pid
func (p *ProcessState) String() string //獲取進程狀態的字符串表示
func (p *ProcessState) Success() bool //判斷程序是否成功退出,而Exited則僅僅只是判斷其是否退出
func (p *ProcessState) Sys() interface{} //返回有關進程的系統獨立的退出信息。並將它轉換爲恰當的底層類型(比如Unix上的syscall.WaitStatus),主要用來獲取進程退出相關資源。
func (p *ProcessState) SysUsage() interface{} //SysUsage返回關於退出進程的系統獨立的資源使用信息。主要用來獲取進程使用系統資源
func (p *ProcessState) SystemTime() time.Duration //獲取退出進程的內核態cpu使用時間
func (p *ProcessState) UserTime() time.Duration //返回退出進程和子進程的用戶態CPU使用時間
func main() {
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, //其他變量如果不清楚可以不設定
}
p, err := os.StartProcess("/usr/bin/vim", []string{"/usr/bin/vim", "tmp.txt"}, attr) //vim 打開tmp.txt文件
if err != nil {
fmt.Println(err)
}
ps, _ := p.Wait() //當關閉vim打開的tmp.txt時,進程就結束了
fmt.Println(ps) //exit status 0
if ps.Exited() {
fmt.Println(ps.Pid()) //536
fmt.Println(ps.String()) // exit status 0
fmt.Println(ps.Success()) //true
fmt.Println(ps.Sys()) //0
fmt.Println(ps.SysUsage()) //&{{0 313157} {0 42898} 29164 0 0 0 7745 41 0 10736 240 0 0 0 1238 143}
fmt.Println(ps.SystemTime()) // 42.898ms
fmt.Println(ps.UserTime()) //313.157ms
}
}
type Signal
type Signal interface {
String() string
Signal() // 同其他字符串做區別
}
代表操作系統的信號.底層的實現是操作系統獨立的:在Unix中是syscal.Signal.
var (
Interrupt Signal = syscall.SIGINT
Kill Signal = syscall.SIGKILL
)
在所有系統中都能夠使用的是interrupe,給進程發送一個信號,強制殺死該進程type SyscallError //SyscallError記錄了一個特定系統調用的錯誤,主要用來返回SyscallError的字符串表示
type SyscallError struct {
Syscall string
Err error
}
func (e *SyscallError) Error() string //返回SyscallError的字符串表示