Golang 文件及目录操作

文件操作:打开和关闭文件  os.Open()、file.Close()

  • 读取文件
    • file.Read() 读取文件
    • bufio 读取文件
    • ioutil 读取整个文件
  • 写入文件  os.OpenFile()
    • Write 和 WriteString
    • bufio.NewWriter
    • ioutil.WriteFile
  • 重命名文件  os.Rename()
  • 复制文件:自定义复制函数

目录操作:

  • 创建目录  os.Makedir()、os.MakedirAll()                        // 创建多级目录,需注意文件权限问题
  • 删除目录或文件  os.Remove()、os.RemoveAll()

打开和关闭文件

import (
	"fmt"
	"os"
)

func main() {
	// 以只读的方式打开文件:os包,func Open(name string) (*File, error)
	file, err := os.Open("./main.go")
	if err != nil {
		fmt.Println("open file failed", err)
		return
	}
	fmt.Println(file) // &{0x14000116120}

	// 关闭文件
	defer file.Close() // 为了防止忘记关闭文件,通常使用 defer 注册文件关闭语句
}

读取文件

「 file.Read() 读取文件 」

func main() {
	// 以只读方式打开文件
	file, err := os.Open("./main.go")
	if err != nil {
		fmt.Println("file open failed")
		return
	}
	defer file.Close() // 关闭文件

	// 读取文件
	tmp := make([]byte, 128) // 设置每次读取128个字节
	// 基本语法:func (f *File) Read(b []byte) (n int, err error)
	// 作用:它接收一个字节切片,返回读取的字节数和可能的具体错误;读到文件末尾时,会返回 0 和 io.EOF
	n, err := file.Read(tmp)
	if err == io.EOF {
		fmt.Println("文件读完了")
		return
	}
	if err != nil {
		fmt.Println("file read failed")
		return
	}
	fmt.Printf("读取了%v个字节 \n", n) // 读取了128个字节
	fmt.Println(string(tmp[:n])) // 说明:打印main.go中的128个文件(但文件未读完)

	// 使用for循环,读取文件中的所有数据
	var content []byte
	var tmp1 = make([]byte, 128)
	for {
		n1, err := file.Read(tmp1)
		if err == io.EOF {
			fmt.Println("文件读完了")
			break
		}
		if err != nil {
			fmt.Println("file read failed")
			return
		}
		content = append(content, tmp1[:n1]...)
	}
	fmt.Println(string(content))
}

「 bufio 读取文件 」bufio 是在 io 的基础上封装了一层 API,支持更多的功能

func main() {
	// 以只读方式打开文件
	file, err := os.Open("./main.go")
	if err != nil {
		fmt.Println("file open failed", err)
		return
	}
	defer file.Close() // 关闭文件

	// bufio 读取文件
	reader := bufio.NewReader(file)
	for {
		// 按行读取
		line, err := reader.ReadString('\n') // 注意是字符
		if err == io.EOF {
			//if len(line) != 0 {
			//	fmt.Println(line)
			//}
			fmt.Println("文件读完了")
			break
		}
		if err != nil {
			fmt.Println("file read err", err)
			return
		}
		fmt.Println(line)
	}
}

ioutil.ReadFile( 已废弃 )读取整个文件 」io/ioutil 包的 ReadFile 能够读取完整的文件,只需要将文件名作为参数传入

func main() {
	content, err := ioutil.ReadFile("./main.go")  // 需说明的是,新版本已废弃这种用法
	if err != nil {
		fmt.Println("file read failed", err)
		return
	}
	fmt.Println(string(content))
}

写入文件

os.OpenFile() 函数,能够以指定模式打开文件,从而实现文件写入相关功能

func OpenFile(name string, flag int, perm FileMode) (*File, error)

// 说明:
   // name,要打开的文件名
   // flag,打开文件的模式,可以有多个,使用 | 分隔
        os.O_WRONLY  只写
        os.O_CREATE  创建文件
        os.O_RDONLY  只读
        os.O_RDWR    读写
        os.O_TRUNC   清空
        os.O_APPEND  追加
   // perm,文件权限,一个八进制数,类似于linux文件权限,如:0777、0666

「 file.Write / file.WriteString 」

	file, err := os.OpenFile("./hello.md", os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		fmt.Println("file open failed", err)
		return
	}
	defer file.Close()

	str := "hello world"
	file.Write([]byte(str))        // Write,写入字节切片数据
	file.WriteString("HelloWorld") // WriteString,可以直接写入字符串数据

「 bufio.NewWriter 」

	file, err := os.OpenFile("./hello.md", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("file open failed", err)
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	for i := 0; i < 5; i++ {
		writer.WriteString("hello\r\n") // 先将数据写入缓存
	}
	writer.Flush() // 然后,将缓存中的内容写入文件

「 ioutil.WriteFile( 已废弃 ) 」

	str := "world"
	// ioutil.WriteFile 已废弃
	err := ioutil.WriteFile("./hello.md", []byte(str), 0666)
	if err != nil {
		fmt.Println("file write failed", err)
		return
	}

重命名文件

	// 文件重命名
	err := os.Rename("./hello.md", "./world.md")
	if err != nil {
		fmt.Println("file rename failed")
		return
	}
	fmt.Println("file rename success")

复制文件

func main() {

	srcFile := "./hello.md"
	dstFile := "./world.md"
	// 方法1
	err := CopyFile(srcFile, dstFile)
	// 方法2
	//err := CopyFile1(srcFile, dstFile)
	if err != nil {
		fmt.Println("copy failed")
	}
	fmt.Println("copy success")
}

// 方法1 - 自定义函数:复制文件
func CopyFile(srcFile string, dstFile string) error {
	// 读取文件
	fileSlice, err := ioutil.ReadFile(srcFile)
	if err != nil {
		return err
	}
	// 写入文件
	err = ioutil.WriteFile(dstFile, fileSlice, 0666)
	if err != nil {
		return err
	}
	return nil
}

// 方法2 - 自定义函数:以方法流的方式,赋值文件
func CopyFile1(srcFile string, dstFile string) error {
	source, _ := os.Open(srcFile)
	destination, _ := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY, 0666)

	buf := make([]byte, 128)
	for {
		n, err := source.Read(buf)
		if err != nil && err != io.EOF {
			return err
		}
		if n == 0 {
			break
		}
		if _, err := destination.Write(buf[:n]); err != nil {
			return err
		}
	}
	return nil
}

目录操作

「 创建目录 」

	// (1)创建单个目录
	// err := os.Mkdir("./abc", 0666)
	//	if err != nil {
	//		fmt.Println(err)
	//	}
	// 如果文件已存在,会报错:mkdir ./abc: file exists,实际上并不需要关心它,所以,如下即可:
	os.Mkdir("./abc", 0666) // 不需要处理错误

	// (2)创建多级目录
	//err := os.MkdirAll("dir1/dir2/dir3", 0777)
	//if err != nil {
	//	fmt.Println(err)  // 会报错 mkdir dir1/dir2: permission denied
	//}

	// 解决方式1:先创建文件,然后,在改变文件的权限
	err := os.MkdirAll("dir1/dir2/dir3", 0777)
	if err != nil {
		fmt.Println(err) // 会报错 mkdir dir1/dir2: permission denied
		os.Chmod("dir1", 0777)
		os.Chmod("dir1/dir2", 0777)
		os.Chmod("dir1/dir2/dir3", 0777)
	}
	// 解决方式2:改变 `umask` 后再创建文件,其后再把 `umask` 改为原来的 umask
	mask := syscall.Umask(0)  // 改为 0000 八进制
	defer syscall.Umask(mask) // 改为原来的umask
	err = os.MkdirAll("dir4/dir5/dir6", 0766)
	if err != nil {
		fmt.Println(err)
	}

「 删除目录和文件 」

	// 删除一个文件或目录
	err := os.Remove("./hello.md")
	if err != nil {
		fmt.Println(err)
	}
	
	// 递归删除
	err = os.RemoveAll("./dir1")
	if err != nil {
		fmt.Println(err)
	}