Featured image of post golang学习十六:文件操作

golang学习十六:文件操作

os包结构介绍

  • Go语言标准库中os包提供了不依赖平台的操作系统接口
  • 设计为Unix风格的,而错误处理是go风格的,失败的调用会返回错误值而非错误码。通常错误值里包含更多信息
  • os包及子包功能
1
2
3
4
-- os 
  --os/exec ,负责执行外部命令.
  --os/signal对输入信息的访问
  --os/user 通过名称或ID	查询用户账户
  • 在os/user中提供了User结构体,表示操作系统用户
    • Uid 用户id
    • Gid 所属组id
    • Username 用户名
    • Name 所属组名
    • HomeDir 用户对应文件夹路径
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// User represents a user account.
type User struct {
	// Uid is the user ID.
	// On POSIX systems, this is a decimal number representing the uid.
	// On Windows, this is a security identifier (SID) in a string format.
	// On Plan 9, this is the contents of /dev/user.
	Uid string
	// Gid is the primary group ID.
	// On POSIX systems, this is a decimal number representing the gid.
	// On Windows, this is a SID in a string format.
	// On Plan 9, this is the contents of /dev/user.
	Gid string
	// Username is the login name.
	Username string
	// Name is the user's real or display name.
	// It might be blank.
	// On POSIX systems, this is the first (or only) entry in the GECOS field
	// list.
	// On Windows, this is the user's display name.
	// On Plan 9, this is the contents of /dev/user.
	Name string
	// HomeDir is the path to the user's home directory (if they have one).
	HomeDir string
}
  • 在os/user中的Group表示用户所属组
    • Gid 组的id
    • Name 组的名称
1
2
3
4
5
6
7
// Group represents a grouping of users.
//
// On POSIX systems Gid contains a decimal number representing the group ID.
type Group struct {
	Gid  string // group ID
	Name string // group name
}
  • 整个os/user包中内容比较少,提供了两个错误类型和获取当前用户,查找用户
1
2
3
4
5
6
7
8
type UnknownUserError
  func (e UnknownUserError) Error() string
type UnknownUserIdError
  func (e UnknownUserIdError) Error() string
type User
  func Current() (*User, error)
  func Lookup(username string) (*User, error)
  func LookupId(uid string) (*User, error)

代码示例

  • 可以获取当前用户或查找用户后获取用户信息
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
   //获取当前登录用户
   //u,_:=user.Current()
   /*
   Lookup()参数是用户名,按照用户名查找指定用户对象
   注意:必须使用完整名称不可以只写zhang
    */
   u, _ := user.Lookup(`LAPTOP-APM56\maishuren`)
   fmt.Println(u.Name)
   fmt.Println(u.Gid)
   fmt.Println(u.HomeDir)
   fmt.Println(u.Uid)
   fmt.Println(u.Username)

os包内容介绍

  • 使用os包中内容进行操作系统文件或目录
  • File结构体表示操作系统文件(夹)
1
2
3
4
// File represents an open file descriptor.
type File struct {
	*file // os specific
}
1
2
3
4
5
6
7
8
9
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
// to close the wrong file descriptor.
type file struct {
	pfd     poll.FD
	name    string
	dirinfo *dirInfo // nil unless directory being read
}
  • 操作系统的文件都是有权限控制的,包含可读,可写等,在os包中FileMode表示文件权限,本质是uint32,可取值都以常量形式提供
1
2
3
4
5
6
// A FileMode represents a file's mode and permission bits.
// The bits have the same definition on all systems, so that
// information about files can be moved from one system
// to another portably. Not all bits apply to all systems.
// The only required bit is ModeDir for directories.
type FileMode uint32
 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
// The defined file mode bits are the most significant bits of the FileMode.
// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
// The values of these bits should be considered part of the public API and
// may be used in wire protocols or disk representations: they must not be
// changed, although new bits might be added.
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; Plan 9 only
	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 // Unix permission bits
)
  • FIleInfo是一个interface表示文件的信息
1
2
3
4
5
6
7
8
9
// A FileInfo describes a file and is returned by Stat and Lstat.
type FileInfo interface {
	Name() string       // base name of the file
	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)
}

资源路径

  • 在获取系统资源时资源路径分为相对路径和绝对路径
  • 相对路径:在Go语言中相对路径用于是GOPATH,也就是项目的根目录
  • 绝对路径:磁盘根目录开始表示资源详细路径的描述

代码示例

  • Go语言标准库中提供了两种创建文件夹的方式
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
	/*
	要求文件夹不存在且父目录必须存在,才能创建
	 */
	//error := os.Mkdir("D:/godir", os.ModeDir)
	//if error != nil {
	//	fmt.Println("文件夹创建失败",error)
	//	return
	//}
	//fmt.Println("文件夹创建成功")


	/*
	如果文件夹已经存在,不报错,保留原文件夹
	如果父目录不存在帮助创建
	 */
	error := os.MkdirAll("D:/godir/a/b", os.ModeDir)
	if error != nil {
		fmt.Println("文件夹创建失败",error)
		return
	}
	fmt.Println("文件夹创建成功")
  • 创建空文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
	/*
	创建文件时要求文件目录必须已经存在
	如果文件已经存在则会创建一个空文件覆盖之前的文件
	 */
	file, err := os.Create("D:/godir/test.txt")
	if err != nil {
		fmt.Println("文件创建失败,", err)
		return
	}
	fmt.Println("文件创建成功",file.Name())
  • 重命名文件或文件夹
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
	/*
	第一个参数:原文件夹名称,要求此路径是必须存在的
	第二个参数:新文件夹名称
	 */
	err := os.Rename("D:/godir", "D:/godir1")
	if err != nil {
		fmt.Println("重命名文件夹失败,", err)
		return
	}
	fmt.Println("文件夹重命名成功")

	/*
	重命名文件和重命名文件夹用法相同
	 */
	err = os.Rename("D:/godir1/test.txt", "D:/godir1/test1.txt")
	if err != nil {
		fmt.Println("重命名文件失败,", err)
		return
	}
	fmt.Println("文件重命名成功")
  • 获取文件(夹)信息
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
	f, err := os.Open("D:/godir1/test1.txt")
	defer f.Close() //文件打开后要关闭,释放资源
	if err != nil {
		fmt.Println("打开文件失败", err)
		return
	}
	fileInfo, err := f.Stat()
	if err != nil {
		fmt.Println("获取文件信息失败", err)
		return
	}
	fmt.Println(fileInfo.Name())    //文件名
	fmt.Println(fileInfo.IsDir())   //是否是文件夹,返回bool,true表示文件夹,false表示文件
	fmt.Println(fileInfo.Mode())    //文件权限
	fmt.Println(fileInfo.ModTime()) //修改时间
	fmt.Println(fileInfo.Size())    //文件大小
  • 删除文件或文件夹
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
	/*
	删除的内容只能是一个文件或空文件夹且必须存在
	 */
	//err := os.Remove("D:/godir1/a")
	//if err != nil {
	//	fmt.Println("文件删除失败", err)
	//	return
	//}
	//fmt.Println("删除成功")

	/*
	只要文件夹存在,删除文件夹.
	无论文件夹是否有内容都会删除
	如果删除目标是文件,则删除文件
	 */
	err := os.RemoveAll("D:/godir1/a.txt")
	if err != nil {
		fmt.Println("删除失败", err)
		return
	}
	fmt.Println("删除成功")

输入流

  • 流(stream)是应用程序和外部资源进行数据交互的纽带

  • 流分为输入流和输出流,输入和输出都是相对于程序,把外部数据传入到程序中叫做输入,反之叫做输出流

  • 输入流(Input Stream),输入流(Output Stream) 平时所说的I/O流

  • 在Go语言标准库中io包下是Reader接口表示输入流,只要实现这个接口就属于输入流

 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
// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
//
// When Read encounters an error or end-of-file condition after
// successfully reading n > 0 bytes, it returns the number of
// bytes read. It may return the (non-nil) error from the same call
// or return the error (and n == 0) from a subsequent call.
// An instance of this general case is that a Reader returning
// a non-zero number of bytes at the end of the input stream may
// return either err == EOF or err == nil. The next Read should
// return 0, EOF.
//
// Callers should always process the n > 0 bytes returned before
// considering the error err. Doing so correctly handles I/O errors
// that happen after reading some bytes and also both of the
// allowed EOF behaviors.
//
// Implementations of Read are discouraged from returning a
// zero byte count with a nil error, except when len(p) == 0.
// Callers should treat a return of 0 and nil as indicating that
// nothing happened; in particular it does not indicate EOF.
//
// Implementations must not retain p.
type Reader interface {
	Read(p []byte) (n int, err error)
}

代码演示

  • 可以使用strings包下的NewReader创建字符串流
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
	r := strings.NewReader("hello 世界")
	b := make([]byte, r.Size())//创建字节切片,存放流中数据,根据流数据大小创建切片大小
	n, err := r.Read(b)//把流中数据读取到切片中
	if err != nil {
		fmt.Println("读取失败,", err)
		return
	}
	fmt.Println("读取数据长度,", n)

	fmt.Println("流中数据",string(b))//以字符串形式输入切片中数据
  • 最常用的是文件流,把外部文件中数据读取到程序中
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
	f, err := os.Open("D:/go.txt")//打开文件
	defer f.Close()
	if err != nil {
		fmt.Println("文件读取失败,", err)
		return
	}
	fileInfo, err := f.Stat()//获取文件信息
	if err != nil {
		fmt.Println("文件信息获取失败,", err)
		return
	}
	b := make([]byte, fileInfo.Size())//根据文件中数据大小创建切片
	_, err = f.Read(b)//读取数据到切片中
	if err != nil {
		fmt.Println("文件流读取失败:", err)
		return
	}
	fmt.Println("文件中内容为:", string(b))//以字符串形式输入切片中数据

输入流

  • 输入流就是把程序中数据写出到外部资源
  • Go语言标准库中输出流是Writer接口
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
// Write must not modify the slice data, even temporarily.
//
// Implementations must not retain p.
type Writer interface {
	Write(p []byte) (n int, err error)
}

代码操作

  • 注意:输入流时不要使用os.Open()因为这种方式获取的文件是只读的
 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
40
41
42
43
44
45
46
47
48
49
50
	fp := "D:/go.txt"
	/*
	第三个参数表示文件权限
	第 1 位在权限中总是为 0
	第 2 位为 0 表示文件不可以被读, 为 1 表示可以被读
	第 3 位为 0 表示文件不可以被写, 为 1 表示可以被写
	第 4 位为 0 表示文件不可以被执行, 为 1 表示可以被执行
	整理如下:
	   0(0000): 不可读写,不能被执行
	   1(0001): 不可读写,能被执行
	   2(0010): 可写不可读,不能被执行
	   3(0011): 可写不可读,能被执行
	   4(0100): 可读不可写,不能被执行
	   5(0101): 可读不可写,能被执行
	   6(0110): 可读写,不能执行
	   7(0111): 可读写,可执行

	0666:
	第一个 0 表示这个数是 八进制
	第一个 6 表示文件拥有者有读写权限,但没有执行权限
	第二个 6 表示文件拥有者同组用户有读写权限,但没有执行权限
	第三个 6 表示其它用户有读写权限,但没有执行权限

	 */

	//第二个参数表示文件内容追加
	//第三个参数表示创建文件时文件权限
	f, err := os.OpenFile(fp, os.O_APPEND, 0660)
	defer f.Close()
	if err != nil {
		fmt.Println("文件不存在,创建文件")
		f, _ = os.Create(fp)
	}

	/*
	内容中识别特殊字符
	\r\n 换行
	\t 缩进
	 */

	/*
	使用文件对象重写的Writer接口,参数是[]byte
	 */
	f.Write([]byte("使用Writer接口写数据\r\n"))

	/*
	使用stringWriter接口的方法,参数是字符串,使用更方便
	 */
	f.WriteString("写了\t一段\r\n内容123")
	fmt.Println("程序执行结束")

ioutil包

  • ioutil包下提供了对文件读写的工具函数,通过这些函数快速实现文件的读写操作
  • ioutil包下提供的函数比较少,但是都是很方便使用的函数
1
2
3
4
5
6
7
func NopCloser(r io.Reader) io.ReadCloser
func ReadAll(r io.Reader) ([]byte, error)
func ReadFile(filename string) ([]byte, error)
func WriteFile(filename string, data []byte, perm os.FileMode) error
func ReadDir(dirname string) ([]os.FileInfo, error)
func TempDir(dir, prefix string) (name string, err error)
func TempFile(dir, prefix string) (f *os.File, err error)

代码演示

  • 打开完文件后可以使用ReadAll把文件中所有内容都读取到
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
	f, err := os.Open("D:/go.txt")
	defer f.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("文件中内容:\n", string(b))
  • 也可以直接读取文件中内容
1
2
3
4
5
6
	b, err := ioutil.ReadFile("D:/go.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(b))
  • 写文件也很简单,直接使用WriteFile函数即可,但是源码中已经规定此文件只能是可写状态,且不是尾加数据
1
2
3
4
5
6
	err := ioutil.WriteFile("D:/abc.txt", []byte("内容123123"), 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("数据写入成功")
  • 还提供了快速获取某个文件夹中所有文件信息的函数
1
2
3
4
	fs,_:=ioutil.ReadDir("D:/")
	for _,n := range fs {
		fmt.Println(n.Name())
	}

golang学习一:从环境配置开始到HelloWorld入门 golang学习二:golang自带的工具 olang学习三:golang基础语法 golang学习四:流程控制 golang学习五:常用数学函数与数组 golang学习六:for循环 golang学习七:goto和label golang学习八:切片 golang学习九:sort包、map、双向链表、双向循环链表 golang学习十:函数 golang学习十一:包的访问权限、变量作用域、闭包 golang学习十二:值传递和引用传递 golang学习十三:结构体 golang学习十四:golang中的面向对象 golang学习十五:错误异常处理 golang学习十六:文件操作 golang学习十七:反射 golang学习十八:XML操作 golang学习十九:日志 golang学习二十:golang并发编程入门 golang学习二十一:select和GC

Licensed under CC BY-NC-SA 4.0