Stream-based encoding and decoding for processing multiple YAML documents or working with io.Reader and io.Writer interfaces. Use these when reading from or writing to files, network connections, or other I/O streams.
A Decoder reads and decodes YAML values from an input stream.
type Decoder struct {
// Has unexported fields
}Creates a new decoder that reads from an io.Reader.
func NewDecoder(r io.Reader) *Decoderr (io.Reader) - The input stream to read YAML documents from*Decoder - A new decoder instancer beyond the YAML values requestedReads the next YAML-encoded value from the input stream and stores it in the value pointed to by v.
func (dec *Decoder) Decode(v interface{}) (err error)v (interface{}) - Pointer to the variable where the decoded value will be storederr (error) - Returns io.EOF when no more documents are available. Returns *yaml.TypeError for type mismatch errors. Returns nil on success.io.EOF when the stream is exhaustedEnables strict field checking to ensure that keys in decoded mappings exist as fields in the struct being decoded into.
func (dec *Decoder) KnownFields(enable bool)enable (bool) - If true, unknown fields will cause an errorDecode()Reading multiple YAML documents from a file:
package main
import (
"fmt"
"io"
"log"
"os"
"gopkg.in/yaml.v3"
)
type Config struct {
Name string
Version int
}
func main() {
file, err := os.Open("configs.yaml")
if err != nil {
log.Fatal(err)
}
defer file.Close()
decoder := yaml.NewDecoder(file)
// Read multiple documents
for {
var config Config
err := decoder.Decode(&config)
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Printf("Config: %+v\n", config)
}
}type Config struct {
Name string
Port int
}
data := `
name: MyApp
port: 8080
extra: value # This field doesn't exist in Config struct
`
decoder := yaml.NewDecoder(strings.NewReader(data))
decoder.KnownFields(true)
var config Config
err := decoder.Decode(&config)
if err != nil {
// Error: unknown field "extra"
log.Println(err)
}An Encoder writes YAML values to an output stream.
type Encoder struct {
// Has unexported fields
}Creates a new encoder that writes to an io.Writer.
func NewEncoder(w io.Writer) *Encoderw (io.Writer) - The output stream to write YAML documents to*Encoder - A new encoder instancewWrites the YAML encoding of v to the stream.
func (e *Encoder) Encode(v interface{}) (err error)v (interface{}) - The value to encodeerr (error) - Error if encoding fails, nil otherwise--- document separator--- separatorChanges the indentation used when encoding.
func (e *Encoder) SetIndent(spaces int)spaces (int) - Number of spaces to use for indentation. Must be non-negative.spaces is negativeEncode()Closes the encoder by writing any remaining data.
func (e *Encoder) Close() (err error)err (error) - Error if closing fails, nil otherwise"..."Writing multiple YAML documents to a file:
package main
import (
"log"
"os"
"gopkg.in/yaml.v3"
)
type Config struct {
Name string
Version int
}
func main() {
file, err := os.Create("configs.yaml")
if err != nil {
log.Fatal(err)
}
defer file.Close()
encoder := yaml.NewEncoder(file)
defer encoder.Close()
configs := []Config{
{Name: "App1", Version: 1},
{Name: "App2", Version: 2},
{Name: "App3", Version: 3},
}
for _, config := range configs {
err := encoder.Encode(&config)
if err != nil {
log.Fatal(err)
}
}
}
// Output to file:
// name: App1
// version: 1
// ---
// name: App2
// version: 2
// ---
// name: App3
// version: 3encoder := yaml.NewEncoder(os.Stdout)
encoder.SetIndent(4) // Use 4 spaces instead of default 2
defer encoder.Close()
data := map[string]interface{}{
"parent": map[string]interface{}{
"child": map[string]string{
"key": "value",
},
},
}
encoder.Encode(data)
// Output:
// parent:
// child:
// key: valuefunc LoadConfig(filename string) (*Config, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var config Config
decoder := yaml.NewDecoder(file)
decoder.KnownFields(true) // Strict checking
if err := decoder.Decode(&config); err != nil {
return nil, err
}
return &config, nil
}func SaveConfig(filename string, config *Config) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := yaml.NewEncoder(file)
defer encoder.Close()
return encoder.Encode(config)
}func ProcessYAMLStream(r io.Reader) error {
decoder := yaml.NewDecoder(r)
for {
var doc map[string]interface{}
err := decoder.Decode(&doc)
if err == io.EOF {
break
}
if err != nil {
return err
}
// Process document
processDocument(doc)
}
return nil
}func YAMLToJSON(r io.Reader, w io.Writer) error {
decoder := yaml.NewDecoder(r)
encoder := json.NewEncoder(w)
for {
var data interface{}
err := decoder.Decode(&data)
if err == io.EOF {
break
}
if err != nil {
return err
}
if err := encoder.Encode(data); err != nil {
return err
}
}
return nil
}Both Decoder.Decode and Encoder.Encode can return errors:
Decode when no more documents are availabledecoder := yaml.NewDecoder(reader)
var config Config
err := decoder.Decode(&config)
switch {
case err == io.EOF:
// No more documents
case err != nil:
if typeErr, ok := err.(*yaml.TypeError); ok {
// Handle type errors
for _, e := range typeErr.Errors {
log.Println(e)
}
} else {
// Handle other errors
log.Fatal(err)
}
}yaml.Marshal and yaml.Unmarshal instead (see Basic YAML Operations)Close() to ensure data is flushed