Golang:JSON,YAML,TOML(配置)文件读数。
#go #100daysofgolang

读取特定文件类型(JSON,YAML,TOML)

在上一篇文章中,我们已经看到了如何读取Golang的文件,在该部分的这一扩展帖子中,我们将研究读取用于配置和存储数据的一些特定文件,例如JSON,YAML,TOML,TOML,CSV等。

我们将看到如何读取文件并在文件中获取单个作品。我们将使用osioutilencoding之类的软件包在文件和文件对象上执行阅读操作。

阅读JSON文件

golang对读取JSON文件有内置的支持,但是我们仍然可以而且需要对如何解析和从文件中提取内容进行低级控制。

假设我们有一个名为blog.jsonjson文件,我们可以使用encoding/json软件包将JSON数据转换为GO对象(一个本机且可以理解的对象)。 Unmarshal函数用于将字节的切片从文件转换为映射对象。

{
    "title": "Golang Blog Series",
    "date": "22nd October 2022",
    "tags": ["go", "files"],
    "words": 1500,
    "published": true
}

以上是一个简单的JSON文件,此文件具有几种类型的键值对,例如字符串,列表,整数和布尔值。但是我们也可以拥有嵌套对象的嵌套对象。

package main

import (
    "encoding/json"
    "log"
    "os"
)

func main() {

    f, err := os.ReadFile("blog.json")
    if err != nil {
        log.Println(err)
    }
    var data map[string]interface{}
    json.Unmarshal([]byte(f), &data)

    log.Println(data)
    for k, v := range data {
        log.Println(k, ":", v)
    }

}

我已经从下面的日志中删除了时间戳,以清楚地看到输出。我们可以使用fmt来打印简单的东西,同时与系列中的其余片段保持一致。

$ go run json.go

map[date:22nd October 2022 published:true tags:[go files] title:Golang Blog Series words:1500]
published : true
title : Golang Blog Series
date : 22nd October 2022
tags : [go files]
words : 1500

使用os.ReadFile方法读取文件,该方法将字符串作为文件路径,并返回字节片或错误,如果读取文件有问题。 Byte的分析切片比作为encoding/json软件包中的Unmarshal方法的第一个参数传递。第二个参数是输出参考,其中将存储或返回解析的JSON。该函数不会返回解析的内容而不是在解析JSON内容时返回错误。

正如我们所看到的那样,我们有一张带有interfacestring的地图。之所以使用界面,是因为键的值可以是任何东西。没有像stringintboolmapslice这样的固定值。因此,我们将JSON对象映射为带有interfacestring的地图。该值的类型与已连接到其上的接口一起标识。让我们看一下地图中每个值的类型是什么。

published : true
bool

title : Golang Blog Series
string

date : 22nd October 2022
string

tags : [go files]
[]interface {}

words : 1500
float64

在这里,我们可以看到它已经正确地识别了bool的字段类型,例如bool或false,即用于字符串的值的字符串类型的字符串,但是第四个字段具有附加的列表接口。 float64超过整数的默认优先级是1500值类型float64的原因。

阅读yaml文件

尽管Golang中没有用于解析/删除YAML文件的标准软件包,但使用第三方软件包很容易使用它来读取YAML文件。

软件包gopkg.in/yaml.v3用于编码和解码YAML文件。我们将仅通过读取并将文件对象转换为本机GO对象(例如地图,列表,字符串等)来解码YAML文件。

以下步骤可用于设置软件包并在本地安装YAML软件包。

go mod init <your_project_package_name>
go get gopkg.in/yaml.v3

这应该创建两个文件,即go.modgo.sum,具有gopkg.in/yaml.v3软件包的依赖性。

title: "Golang Blog Series"
date: "22nd October 2022"
tags: ["go", "files"]
published: false
words: 1500

上面的文件是一个简单的YAML配置,我们将按照示例中使用的虚拟文件进行类似的示例。

package main

import (
    "log"
    "os"

    yaml "gopkg.in/yaml.v3"
)

func main() {

    f, err := os.ReadFile("blog.yaml")

    if err != nil {
        log.Fatal(err)
    }

    var data map[string]interface{}

    err = yaml.Unmarshal(f, &data)

    if err != nil {
        log.Fatal(err)
    }

    log.Println(data)
    for k, v := range data {
        log.Println(k, ":", v)
    }
}
$ go run yaml.go

map[date:22nd October 2022 published:false tags:[go files] title:Golang Blog Series words:1500]
published : false
words : 1500
title : Golang Blog Series
date : 22nd October 2022
tags : [go files]

上面的代码和输出演示了用于读取YAML文件的yaml.v3软件包的使用。

首先,我们使用os.ReadFile()方法将文件读取为单弦对象。该方法将返回[]byte(字节切片)或错误。如果存在错误,我们简单地将程序记录在程序中,否则我们可以使用yaml.Unmarshal方法将字节的字符串/切片转换为地图或预定义的结构。在此示例中,我们只通过将文件内容存储为map [string, interface{}],即stringinterface的地图来保持简单。 YAML的关键只能是字符串或整数。它不能像该值那样具有不受限制的数据类型。虽然,如果您想不受限制,则可以使用map[interface{}]interface{}的地图来制作您喜欢的任何形状。

因此,我们创建了一个称为data的变量作为stringinterface{}的映射,基本上可以是字符串,并且该值可以是任何类型的接口,具体取决于从文件对象中分析的。 Unmarshal函数采用两个参数,第一个是字节的切片,即文件内容,第二个是输出变量。现在,该方法不返回解析的YAML,如果出现了,它可以返回错误,因此我们需要将第二个参数设置为我们要存储解析的yaml的对象的指针。

在示例中,我们称为Unmarshal(f, &data),它将从字节f的切片中获取内容,并输出从字节切片中解析的yaml到data的内存位置,因此使用&data指示可变的指示器内存地址)。

因此,这就是我们从YAML配置获得键和值地图的方式,此后,您可以在地图上迭代,访问键和值,按要求键入铸件,并基本上控制着什么处理需要对解析的YAML内容进行。

published : false
bool

words : 1500
int

title : Golang Blog Series
string

date : 22nd October 2022
string

tags : [go files]
[]interface {}

我刚刚将上面输出中值的类型打印为log.Printf("%T", v),我们可以看到这些类型已正确识别并被解析。最后一个对象确实是一个slice,因此它具有连接到它的切片(数组)的接口。

阅读toml文件

YAML和TOML几乎是相同的,尽管TOML具有更限制的配置选项,但是比YAML更可读,因为YAML很快就会变得复杂。尽管他们俩都有其优点和缺点,但YAML在DevOps World中无处不在,而TOML是Python包装的首选格式,静态站点生成配置。

让我们看看如何使用Golang读取TOML文件。

$ go mod init <your_project_package_name>
$ go get github.com/pelletier/go-toml

上述命令用于设置Golang软件包或项目并安装go-toml软件包。上述命令执行后,它将生成k​​oude21和go.sum文件,用于存储本地项目安装的依赖关系和软件包。

[blog]
name='techstructive-blog'
tags=['go','django','vim']
author='meet gor'
active=true

[author]
name='Meet Gor'
github='mr-destructive'
twitter='meetgor21'
posts=80

以上是示例文件blog.toml,我们将在下面的GO脚本中读取它。 TOML文件的结构与我们在之前的示例中所看到的相似。我们有不同的数据类型,例如字符串,布尔值,整数和列表。

package main

import (
    "log"
    "os"

    toml "github.com/pelletier/go-toml"
)

func main() {

    f, err := os.ReadFile("blog.toml")

    if err != nil {
        log.Fatal(err)
    }

    var data map[interface{}]interface{}

    err = toml.Unmarshal(f, &data)
    log.Println(data)

    if err != nil {
        log.Fatal(err)
    }

    for k, v := range data {
        log.Println(k, ":", v)

        switch t := v.(type) {
        case map[string]interface{}:
            for a, b := range t {
                log.Println(a, ":", b)
            }
        }
    }
}
$ go run toml.go

map[author:map[github:mr-destructive name:Meet Gor posts:80 twitter:meetgor21] blog:map[active:true author:meet gor

name:techstructive-blog tags:[go django vim]]]

blog : map[active:true author:meet gor name:techstructive-blog tags:[go django vim]]
name : techstructive-blog
tags : [go django vim]
author : meet gor
active : true

author : map[github:mr-destructive name:Meet Gor posts:80 twitter:meetgor21]

name : Meet Gor
github : mr-destructive
twitter : meetgor21
posts : 80

因此,在上面的示例和输出中,读取YAML文件,并读取其中的键值对。我们要做的第一件事是使用ioutil软件包读取文件blog.toml,并使用ReadFile函数。该函数将字符串作为要读取文件的路径并返回字节片。我们将此字节片用作Unmarshal方法的参数。 Unmarshal的第二个参数是输出变量(通常是变量的指针),我们已经创建了用interfaceinterface{]的地图,因为我们看到的是嵌套键,该键容纳配置的名称。

变量datainterface{}interface{}的地图,我们将内存地址解析为data变量Unmarshal方法。因此,解析的TOML内容存储在数据变量中。

name : techstructive-blog
string

tags : [go django vim]
[]interface{}

author : meet gor
string

active : true
bool

name : Meet Gor
string

github : mr-destructive
string

twitter : meetgor21
string

posts : 80
int64

上面是Golang解析的值类型的详细输出,我们具有stringboolint64和一个slice(带有接口{}的列表)。只能从unmarshal函数中解析stringboolintint,除了这些类型之外,该类型将附带一个接口。

在这种情况下,如果值类型不属于4种类型(字符串,bool,int float),则可以使用预定义的结构来解析文件中的内容。尽管它需要严格的结构和可预测的响应。

读取CSV文件

我们甚至可以在Golang中读取CSV文件,我们在上一篇文章中看到了我们在文件解析中使用的自定义定界符。

id,name,posts,exp
21,jim,23,2
33,kevin,39,1
45,james,70,2
56,chris,89,3

上面的文件是示例CSV文件,尽管大小太小,但我们可以用作示例。

package main

import (
    "encoding/csv"
    "log"
    "os"
)

func main() {
    f, err := os.Open("temp.csv")
    check_error(err)

    reader := csv.NewReader(f)

    n, err := reader.ReadAll()
    check_error(err)
    for _, line := range n {
        for _, text := range line {
            log.Println(text)
        }
    }
}
$ go run main.go
id
name
posts
exp
21
jim
23
2
33
kevin
39
1
45
james
70
2
56
chris
89
3

CSV软件包具有NewReader方法,该方法接受io.Reader并返回Reader对象。解析读者后,我们使用ReadAll方法在解析内容时返回2D字符串或错误。您可以在previous post中获得CSV解析和阅读的详细说明。

从URL读取CSV

也可以从URL读取CSV文件,该文件的内容是response.Body代替文件对象引用,在上一个示例中,os.Open()方法返回os.File对象。

我们使用http.Get(string)方法从URL获取响应以读取网络上存在的CSV文件。

package main

import (
    "encoding/csv"
    "log"
    "net/http"
)

func main() {

    url := "https://github.com/woocommerce/woocommerce/raw/master/sample-data/sample_products.csv"
    response, err := http.Get(url)

    if err != nil {
        log.Println(err)
        return
    }

    defer response.Body.Close()

    reader := csv.NewReader(response.Body)
    n, err := reader.ReadAll()

    if err != nil {
        log.Println(err)
    }

    for _, line := range n {
        for _, text := range line {
            log.Println(text)
        }
    }
}
$ go run csv.go
<feff>ID
Type
SKU
Name
Published
Is featured?
Visibility in catalog
Short description
Description
Date sale price starts
Date sale price ends
...
...
...

因此,这就是我们可以从URL读取CSV文件的方式。通过从http.Get方法中获取CSV URL https://github.com/woocommerce/woocommerce/raw/master/sample-data/sample_products.csv,这将使我们获得包含实际CSV文件内容的response.Body。反应比可以解析为csv.NewReader(*Os.File).ReadAll(),即reader.ReadAll()。该函数返回可以根据要求进行迭代和解析的多维切片[][]slice

读取XML文件

XML是RSS提要的事实上的标准,它在许多地方被广泛使用,并且仍然遍布整个网络。我们将看到一个示例可以在本地读取XML文件,但是正如我们在上面的示例中看到的,我们还可以从Web中读取RSS链接。

就像CSV一样,我们有encoding/xml,并且标准库具有用于解析XML文件的所有功能。

我们将使用一个名为rss.xml的本地XML文件,并从文件中的标签中读取内容。

<?xml version="1.0" encoding="UTF-8" ?>
<channel>
<title>Meet Gor</title>
<description>Techstructive Blog Feed</description>
<item>
<title>Why and How to make and use Vim as a text editor and customizable IDE</title>
<link>https://www.meetgor.com/vim-text-editor-ide</link>
</item>
<item>
<title>Setting up Vim for Python</title>
<link>https://www.meetgor.com/vim-for-python</link>
</item>
</channel>

上面的示例是我博客rss feed的一小部分。我刚刚修剪了不需要的部分,只会使用我们要获取的标签。

package main

import (
    "encoding/xml"
    "log"
    "os"
)

type Channel struct {
    XMLName     xml.Name `xml:"channel"`
    Title       string   `xml:"title"`
    Description string   `xml:"description"`
    Item        []Item   `xml:"item"`
}

type Item struct {
    XMLName xml.Name `xml:"item"`
    Title   string   `xml:"title"`
    Link    string   `xml:"link"`
}

func check_error(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func main() {

    f, err := os.ReadFile("rss.xml")
    check_error(err)
    defer f.Close()

    d := Channel{}
    err = xml.Unmarshal(f, &d)
    check_error(err)

    for _, item := range d.Item {
        log.Println(item.Title)
    }
}
$ go run xml.go

{{ channel} Meet Gor Techstructive Blog Feed [{{ item} Why and How to make and use Vim as a text editor and customizable IDE https://www.meetgor.com/vim-text-editor-ide} {{ item} Setting up Vim for Python https://www.meetgor.com/vim-for-python}]}

Why and How to make and use Vim as a text editor and customizable IDE
Setting up Vim for Python

上面的示例使用了几个struct,例如ChannelItem,它们存储了标签数据,例如titledescriptionlink等。与json,yaml和toml文件不同,xml不能直接解析我们需要的内容。分析的结构。这很好,因为XML在配置方面并不多,我们通常具有标准标签和元素,可以在结构类型中预定。

在此示例中,RSS feed具有带有titledescriptionitemChannel标签。

注意:将标题案例用于结构的字段。这将使田野公开,我花了几个小时调试,真的:)

因此,我们将带有Title之类的字段的Channel结构定义为字符串,该字符串是文件中的标签,为xml:"title"。这意味着XML标签中的标题将以属性名称为Title中的字符串存储在字段中。同样,我们有像DescriptionItem[]这样的字段,这是XML文件中可能存在的item标签的列表或多个。 XMLName用于识别结构的父标签,因此我们将channel用于第一个结构,因为它是XML文件中层次结构的第一个标签。

因此,我们为Channel{}(一个空对象实例化)创建一个根结构的对象。 xml.Unmarshal函数用文件的内容为data,这是我们在上一个示例中看到的字节片。然后,在Unmarshal方法中使用字节的切片作为第一个参数,并将空的Channel对象作为第二个参数的引用。第二个参数将是存储文件中解析的XML内容。

我在GitHub存储库上有一些示例,其中涵盖了CSV和XML文件的URL读取文件。但是,在示例中,此概念也可以应用于JSON,YAML和其他文件格式。

就是这部分。所有代码示例和命令的参考可以在100 days of Golang GitHub存储库中找到。

结论

因此,从这篇文章中,我们介绍了如何读取特定的配置文件,例如JSONCSVYAMLTOMLXML。我们看到了如何读取本地文件,还涉及该概念以用URL从网络上的文件中读取内容。我们还看到了如何使用预定义的结构从文件中解析内容,尤其是对于XML。

感谢您的阅读。如果您有任何疑问,问题或反馈,可以在下面的讨论中或我的社交手柄上告诉我。快乐编码:)系列:“ [''100天Golang']