Go语言教程之边写边学:读写不同的文件类型

了解如何使用 bufio、encoding和 io 包读取和写入常见文件类型(文本、CSV、JSON 和 XML)中的数据。

 

读取 XML 文件

xml 包包括支持将数据从字节切片解码为值的函数Unmarshal()。该函数用于将 XML 格式文件中的值解码为Notes结构。

notes.xml文件是用os.ReadFile()函数读取的,返回一个字节片,然后使用xml.Unmarshal()函数将其解码为结构实例。结构实例成员值用于打印解码的数据。

<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

package main
 
import (
	"encoding/xml"
	"fmt"
	"os"
)
 
type Notes struct {
	To      string `xml:"to"`
	From    string `xml:"from"`
	Heading string `xml:"heading"`
	Body    string `xml:"body"`
}
 
func main() {
	data, _ := os.ReadFile("notes.xml")
 
	note := &Notes{}
 
	_ = xml.Unmarshal([]byte(data), &note)
 
	fmt.Println(note.To)
	fmt.Println(note.From)
	fmt.Println(note.Heading)
	fmt.Println(note.Body)
}

输出

Tove
Jani
Reminder
Don't forget me this weekend!

 

写入 XML 文件

xml包有一个函数Marshal(),用于从结构序列化值并将其写入XML格式的文件。

notes结构由大写首字母定义,“xml”字段标记用于标识键。初始化结构值,然后使用xml.Marshal()函数进行序列化。接收序列化的XML格式的字节片,然后使用os.WriteFile将其写入文件。

package main
 
import (
	"encoding/xml"
	"os"
)
 
type notes struct {
	To      string `xml:"to"`
	From    string `xml:"from"`
	Heading string `xml:"heading"`
	Body    string `xml:"body"`
}
 
func main() {
	note := ¬es{To: "Nicky",
		From:    "Rock",
		Heading: "Meeting",
		Body:    "Meeting at 5pm!",
	}
 
	file, _ := xml.MarshalIndent(note, "", " ")
 
	_ = os.WriteFile("notes1.xml", file, 0644)
 
}

 

读取 JSON 文件

json包包括支持将数据从字节切片解码为值的函数Unmarshal()。解码后的值通常分配给结构字段,字段名称必须导出,并且应采用大写格式。

JSON文件test.json是使用os.ReadFile()读取的,它返回一个字节片,该片使用Unmarshal()函数把json解码为结构体实例。最后,使用for循环打印结构实例成员值,以证明JSON文件已解码。

package main
 
import (
	"encoding/json"
	"fmt"
	"os"
)
 
type CatlogNodes struct {
	CatlogNodes []Catlog `json:"catlog_nodes"`
}
 
type Catlog struct {
	Product_id string `json: "product_id"`
	Quantity   int    `json: "quantity"`
}
 
func main() {
	file, _ := os.ReadFile("test.json")
 
	data := CatlogNodes{}
 
	_ = json.Unmarshal([]byte(file), &data)
 
	for i := 0; i < len(data.CatlogNodes); i++ {
		fmt.Println("Product Id: ", data.CatlogNodes[i].Product_id)
		fmt.Println("Quantity: ", data.CatlogNodes[i].Quantity)
	}
 
}

 

写入 JSON 文件

json包有一个函数MarshalIndent(),用于从结构序列化值并将其写入JSON格式的文件。

 Salary结构是使用json字段定义的。初始化结构值,然后使用MarshalIndent()进行序列化。接收序列化的JSON格式的字节片,然后使用os.WriteFile()将其写入文件。

package main
 
import (
	"encoding/json"
	"io/ioutil"
)
 
type Salary struct {
        Basic, HRA, TA float64
    }
 
type Employee struct {
	FirstName, LastName, Email string
	Age                        int
	MonthlySalary              []Salary
}
 
func main() {
	data := Employee{
        FirstName: "Mark",
        LastName:  "Jones",
        Email:     "mark@gmail.com",
        Age:       25,
        MonthlySalary: []Salary{
            Salary{
                Basic: 15000.00,
                HRA:   5000.00,
                TA:    2000.00,
            },
            Salary{
                Basic: 16000.00,
                HRA:   5000.00,
                TA:    2100.00,
            },
            Salary{
                Basic: 17000.00,
                HRA:   5000.00,
                TA:    2200.00,
            },
        },
    }
 
	file, _ := json.MarshalIndent(data, "", " ")
 
	_ = ioutil.WriteFile("test.json", file, 0644)
}

输出

{
 "FirstName": "Mark",
 "LastName": "Jones",
 "Email": "mark@gmail.com",
 "Age": 25,
 "MonthlySalary": [
  {
   "Basic": 15000,
   "HRA": 5000,
   "TA": 2000
  },
  {
   "Basic": 16000,
   "HRA": 5000,
   "TA": 2100
  },
  {
   "Basic": 17000,
   "HRA": 5000,
   "TA": 2200
  }
 ]
}

 

读取文本文件

bufio包的Scanner通常用于按行或单词从文件中读取文本。以下源代码片段显示了从纯文本文件中逐行读取文本的过程。

os.Open()函数用于以只读模式打开特定的文本文件,这将返回os.File类型的指针。调用os.File.Close()来关闭os.File类型文件,并且有一个循环来循环访问和打印每个切片值。 执行后的程序在从文件中读取输出时逐行显示以下输出。

package main
 
import (
	"bufio"
	"fmt"
	"log"
	"os"
)
 
func main() {
	file, err := os.Open("test.txt")
 
	if err != nil {
		log.Fatalf("failed opening file: %s", err)
	}
 
	scanner := bufio.NewScanner(file)
	scanner.Split(bufio.ScanLines)
	var txtlines []string
 
	for scanner.Scan() {
		txtlines = append(txtlines, scanner.Text())
	}
 
	file.Close()
 
	for _, eachline := range txtlines {
		fmt.Println(eachline)
	}
}

输出

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc a mi dapibus, faucibus mauris eu, fermentum ligula.
Donec in mauris ut justo eleifend dapibus.
Donec eu erat sit amet velit auctor tempus id eget mauris.

 

写入文本文件

bufio包提供了一种高效的缓冲Writer,它将字节排队直到达到阈值,然后以最少的资源完成对文件的写入操作。以下源代码片段演示如何逐行将字符串切片写入纯文本文件。

sampledata表示为一个字符串切片,其中包含几行数据,这些数据将被写入文件中的新行。函数os.OpenFile()与标志组合一起使用,以创建只写文件(如果不存在),并在写入时附加到该文件。

package main
 
import (
	"bufio"
	"log"
	"os"
)
 
func main() {
	sampledata := []string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
		"Nunc a mi dapibus, faucibus mauris eu, fermentum ligula.",
		"Donec in mauris ut justo eleifend dapibus.",
		"Donec eu erat sit amet velit auctor tempus id eget mauris.",
	}
 
	file, err := os.OpenFile("test.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 
	if err != nil {
		log.Fatalf("failed creating file: %s", err)
	}
 
	datawriter := bufio.NewWriter(file)
 
	for _, data := range sampledata {
		_, _ = datawriter.WriteString(data + "\n")
	}
 
	datawriter.Flush()
	file.Close()
}

 

读取 CSV 文件

csv包有一个函数NewReader(),该函数返回一个Reader对象来处理CSV数据。一个csv.Reader将其输入中的 \r\n 序列仅转换为 \n,其中还包括多行字段值。

test.csv只有几条记录,使用os.Open()函数以只读模式打开,该函数返回os.File的指针类型实例。csv.Reader.Read()方法用于将每个文件记录解码为预定义的结构CSVData,然后将它们存储在切片中,直到返回io.EOF。

package main
 
import (
	"bufio"
	"fmt"
	"log"
	"os"
)
 
func main() {
	file, err := os.Open("test.txt")
 
	if err != nil {
		log.Fatalf("failed opening file: %s", err)
	}
 
	scanner := bufio.NewScanner(file)
	scanner.Split(bufio.ScanLines)
	var txtlines []string
 
	for scanner.Scan() {
		txtlines = append(txtlines, scanner.Text())
	}
 
	file.Close()
 
	for _, eachline := range txtlines {
		fmt.Println(eachline)
	}
}

输出

Name -- City -- Job
John -- London -- CA
Micky -- Paris -- IT

 

写入CSV 文件

csv包有一个函数NewWriter(),该函数返回一个用于写入CSV数据的Writer对象。csv.Writer对象写入由换行符终止的csv记录,并使用逗号作为字段分隔符。以下源代码片段演示如何将数据写入CSV文件。

二维切片行包含示例csv记录。操作系统。os.Create()创建一个csv文件test.csv; 截断它的所有记录(如果已存在)并返回os.File对象。csvwriter.Write(row)方法以将每个字符串切片作为CSV记录写入文件。

package main
 
import (
	"encoding/csv"
	"log"
	"os"
)
 
func main() {
	rows := [][]string{
		{"Name", "City", "Language"},
		{"Pinky", "London", "Python"},
		{"Nicky", "Paris", "Golang"},
		{"Micky", "Tokyo", "Php"},
	}
 
	csvfile, err := os.Create("test.csv")
 
	if err != nil {
		log.Fatalf("failed creating file: %s", err)
	}
 
	csvwriter := csv.NewWriter(csvfile)
 
	for _, row := range rows {
		_ = csvwriter.Write(row)
	}
 
	csvwriter.Flush()
 
	csvfile.Close()
}