Go 文件读写

一、文件读写

1.1.读文件

1.1.1. os.ReadFile
func ReadByOSReadFile() {
	dat, err := os.ReadFile("./main.go")
	// ioutil.ReadFile等同于os.ReadFile
	// dat, err := ioutil.ReadFile("./main.go")
	check(err)
	fmt.Print(string(dat))
}
  • os.ReadFile会把所有文件的所有内容加载到内存,对于简单的小文件可以直接方便地使用
  • 其内部实现就是循环调用file.Read方法将文件内容写入[]byte,直到结束
func ReadFile(name string) ([]byte, error) {
	f, err := Open(name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var size int
	if info, err := f.Stat(); err == nil {
		size64 := info.Size()
		if int64(int(size64)) == size64 {
			size = int(size64)
		}
	}
	size++ // one byte for final read at EOF

	if size < 512 {
		size = 512
	}

	data := make([]byte, 0, size)
	for {
		if len(data) >= cap(data) {
			d := append(data[:cap(data)], 0)
			data = d[:len(data)]
		}
		n, err := f.Read(data[len(data):cap(data)])
		data = data[:len(data)+n]
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return data, err
		}
	}
}
1.1.2. file.Read
  • 当然,我们也可以自己通过file.Read去实现完整地读,具体实现参考os.ReadFile。
  • 自己实现就可以实现一些定制需求,例如,需要从文件的某个位置开始读
func check(e error) {
	if e != nil {
		panic(e)
	}
}

// file.Seek(offset, whence)
// offset:偏移量
// whence:0:从头开始;1: 从当前位置开始;2:从结尾开始

func ReadBySeek() {
	f, err := os.Open("./main.go")
	check(err)
	// 将文件指针移动到 从文件头开始,偏移8位
	// 返回偏移的位置
	o2, err := f.Seek(8, 0)
	check(err)

	// 从当前文件指针位置开始读4个字节
	b2 := make([]byte, 4)
	n2, err := f.Read(b2)
	check(err)
	fmt.Printf("%d bytes @ %d: ", n2, o2)
	fmt.Printf("%v\n", string(b2[:n2]))
}
1.1.3. bufio.NewReader

bufio.NewReader通过缓存去读,对于需要读许多小文件的效率比较高。

func ReadByBufio() {
	f, err := os.Open("./main.go")
	check(err)
	defer f.Close()
	reader := bufio.NewReader(f)
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			if len(line) != 0 {
				fmt.Println(line)
			}
			break
		}
		check(err)
		fmt.Print(line)
	}
}

1.2.写文件

1.2.1. os.OpenFile

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

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

flag常用的几个位如下:

  • os.O_WRONLY
  • os.O_CREATE(文件如果不存在就创建)
  • os.O_RDONLY
  • os.O_RDWR(读写)
  • os.TRUNC(清空文件)
  • os.O_APPEND(追加)
func WriteByOpenFile() {
	// 如果文件不存在,则创建;写入时先请空文件再开始写
	f, err := os.OpenFile("tmp.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
	check(err)
	defer f.Close()
	// 写入bytes
	f.Write([]byte("f.Write \n"))
	// 写入string
	f.WriteString("f.WriteString")
	
	// 通过bufio.NewWriter写入(基于缓存)
	writer := bufio.NewWriter(f)
	for i := 0; i < 3; i++ {
		writer.WriteString("bufio.NewWriter\n") // 先写入缓存
	}
	writer.Flush() // 注意,如果没有flush的话,即使文件关闭了也不会写入文件
}
1.2.2. os.WriteFIle

os.WriteFile内部实现和我们上面写的差不多,OpenFile然后Write

func WriteByOSWriteFile() {

	err := os.WriteFile("tmp.txt", []byte("Write by os.WriteFile\n"), 0644)
	
	// ioutil.WriteFile等同于OSWriteFile
	// err := ioutil.WriteFile("tmp.txt", []byte("Write by ioutil.WriteFile\n"), 0644)
	check(err)
}

二、josn文件读写

2.1.读json文件

读json文件主要就是用json.Unmarshal方法,通常会读到一个map或者对应的结构体中

func ReadJsonFileToMap(filename string) {
	jsonFile, err := os.Open(filename)
	check(err)
	defer jsonFile.Close()
	byteValue, _ := ioutil.ReadAll(jsonFile)
	var result map[string]interface{}
	json.Unmarshal([]byte(byteValue), &result)
	fmt.Println(result["users"])
}
type Social struct {
	Facebook string `json:"facebook"`
	Twitter  string `json:"twitter"`
}

type User struct {
	Name   string `json:"name"`
	Type   string `json:"type"`
	Age    int    `json:"Age"`
	Social Social `json:"social"`
}
type Users struct {
	Users []User `json:"users"`
}

func ReadJsonFileToStruct(filename string) {
	jsonFile, err := os.Open(filename)
	check(err)
	defer jsonFile.Close()
	byteValue, _ := ioutil.ReadAll(jsonFile)
	var users Users
	json.Unmarshal(byteValue, &users)
	for i := 0; i < len(users.Users); i++ {
		fmt.Println("User Type: " + users.Users[i].Type)
		fmt.Println("User Age: " + strconv.Itoa(users.Users[i].Age))
		fmt.Println("User Name: " + users.Users[i].Name)
		fmt.Println("Facebook Url: " + users.Users[i].Social.Facebook)
	}
}

users.json

{
  "users": [
    {
      "name": "Alice",
      "type": "Reader",
      "age": 25,
      "social": {
        "facebook": "https://facebook.com",
        "twitter": "https://twitter.com"
      }
    },
    {
      "name": "Bob",
      "type": "Author",
      "age": 28,
      "social": {
        "facebook": "https://facebook.com",
        "twitter": "https://twitter.com"
      }
    }
  ]
}

2.2.写json文件

写json文件就是Marshal后Write

func DumpJson(users *Users) {
	f, _ := json.MarshalIndent(&users, "", "\t")
	ioutil.WriteFile("users_dump.json", f, 0644)
}

三、yaml文件读写

yaml文件的读写和json类似,都是通过Marshal和UnMarshal


import(
	"gopkg.in/yaml.v3"
	"io/ioutil"
)

type Conf struct {
	Username string `yaml:"Username"`
	Password string `yaml:"Password"`
}

func ReadYaml(string filename){
	buf, err := ioutil.ReadFile(filename)
	check(err)
	var conf Config
	yaml.Unmarshal(buf, &conf)
}


func WriteYaml() {
	conf := Conf{"test", "test",}
	data, _ := yaml.Marshal(&conf)
	fmt.Printf("%v\n", string(data))
	ioutil.WriteFile("config.yaml", data, 0644)
}

Refs

  • https://gobyexample.com/reading-files
  • https://tutorialedge.net/golang/parsing-json-with-golang/
  • https://dev.to/sagartrimukhe/generate-yaml-files-in-golang-29h1

你可能感兴趣的:(Go,Go)