# 写文件

Go 语言中读写文件还是很方便的,但是有一些点还是需要注意

package main
import (
	"fmt"
	"os"
	"time"
)
func main() {
	f, err := os.OpenFile("test",os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)
	if err != nil {
		fmt.Println("error")
	}
	// s := []byte("hello world")
	_, err2 := f.WriteString("hello world! "+time.Now().String()+"\n")
	if err2 != nil{
		fmt.Println("error2")
	}
	defer f.Close()
}

打开文件有 OpenOpenFile 两个 API,但是 OPEN 返回只读的文件句柄,而 OpenFile 可以自定义权限

const (
	// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
	O_RDONLY int = syscall.O_RDONLY // open the file read-only.
	O_WRONLY int = syscall.O_WRONLY // open the file write-only.
	O_RDWR   int = syscall.O_RDWR   // open the file read-write.
	// The remaining values may be or'ed in to control behavior.
	O_APPEND int = syscall.O_APPEND // append data to the file when writing.
	O_CREATE int = syscall.O_CREAT  // create a new file if none exists.
	O_EXCL   int = syscall.O_EXCL   // used with O_CREATE, file must not exist.
	O_SYNC   int = syscall.O_SYNC   // open for synchronous I/O.
	O_TRUNC  int = syscall.O_TRUNC  // truncate regular writable file when opened.
)

O_RDWD 就是读写, O_APPEND 代表以 Append 方式写, O_Create 如果没有文件就创建一个文件。

golang 里写文件如果不是 append 方式的话,那么写文件方式是以写覆盖方式进行的,而不是把文件清空,这点和 python 有一些区别。

如果要清空文件只需要加上 O_TRUNC,

# 按行读取文件

package main
import (
	"bufio"
	"fmt"
	"io"
	"os"
)
func main() {
	f, err := os.OpenFile("test", os.O_CREATE|os.O_RDWR, 0777)
	if err != nil {
		fmt.Println("error")
	}
	i := 0
	reader := bufio.NewReader(f)
	for {
	
		s, err3 := reader.ReadString('\n')
		if err3 == io.EOF {
			fmt.Println("end")
			break
		}
		fmt.Printf("s: %v\n", s)
		fmt.Printf("i: %v\n", i)
		i++
	}
	defer f.Close()
}

这个以 \n 作为分隔符进行读取,原来文件:

image-20220114222752410

这个读取方式不会把最后那个换行读取过去。

# 直接读

b, err2 := ioutil.ReadFile("test")
	if err2 != nil{
		fmt.Println("err")
	}
	all_content := strings.Split(string(b),"\n")
	for _, v := range all_content {
		if v==""{
			continue
		}
		fmt.Printf("v: %v\n", v)
	}

一次性把所有内容读到内存,然后用 split 对 string 做切分,注意!

split 对下面累啦,按 \n 进行切分时:

a\nb\nc\n

它实际上返回了 ["a", "b","c", ""]

最后会有一个空字符。

# 按字节数读

f, _ := os.Open("a.txt")
for {
    buf := make([]byte, 6)
    n, err := f.Read(buf)
    fmt.Println(string(buf))
    fmt.Printf("n: %v\n", n)
    if err == io.EOF {
    	break
    }
}
f.Close()

定义定义一个 buf 大小

os 包还可以做很多,比如对进程进行操作:

golang 标准库 os 包进程相关操作

# 常用的几个 IO 包

ioutil bufio os io

io 包定义了 readerwriter 两个接口,也就说只要实现了这个接口就可以被这些 io 包调用。

image-20220115200648560

比如, ioutil.ReadAll 的接口

func ReadAll(r io.Reader) ([]byte, error)

那么 string.Reader 可以被调用,同时 os.file 也就说 os.Openfile 返回的句柄也可以调用这个 readall

# ioutil

func ReadAll(r io.Reader) ([]byte, error)
func ReadDir(dirname string) ([]fs.FileInfo, error)
func ReadFile(filename string) ([]byte, error)
func TempDir(dir, pattern string) (name string, err error)

这个 TempDir,如果 pattern 中有 * 这个符号,比如 *-logs 这个作为传入的 pattern,那么会生成诸如 238493589-logs 这样一个临时的文件夹,前面数字是随机的,它会取代 * 所在位置。

即使没加 defer os.removeall 它也会自动删除的。

func WriteFile(filename string, data []byte, perm fs.FileMode) error

如果没有文件就创建,如果有文件就清空写,默认使用 truncate 参数。

Flush 用于刷新缓冲区。

# Stdin 和 stdout

这个要查直接看 fmt 文档就行了

要记住的要, %q 输出字符串字面值,比如 hello\nworld

更新于

请我喝[茶]~( ̄▽ ̄)~*

Kalice 微信支付

微信支付

Kalice 支付宝

支付宝