[Golang] Caveat of fmt.Fprintf Use


Do not use fmt.Fprintf to write to file.

The following code writes string to file via fmt.Fprintf:

osfmt.go | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package write

import (
	"fmt"
	"os"
)

func BadWriteStringToFile(filepath, s string) error {
	fo, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer fo.Close()

	_, err = fmt.Fprintf(fo, s)
	if err != nil {
		return err
	}

	return nil
}

The above code is ok if there is no % in the string. What if % in the string?

if err := BadWriteStringToFile("bad.txt", "% in string\n"); err != nil {
      panic(err)
}

The output (bad.txt) is:

%!i(MISSING)n string

This is not the result we want, so what is the good way to write string to file? The answer is use io.Copy:

osiocopy.go | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package write

import (
	"io"
	"os"
	"strings"
)

func WriteStringToFile(filepath, s string) error {
	fo, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer fo.Close()

	_, err = io.Copy(fo, strings.NewReader(s))
	if err != nil {
		return err
	}

	return nil
}

Again write the same string to file:

if err := WriteStringToFile("good.txt", "% in string\n"); err != nil {
      panic(err)
}

The output (good.txt):

% in string

This is the result we want!


Tested on: Ubuntu Linux 16.10, Go 1.8.


References:

[1]os - The Go Programming Language
[2]io - The Go Programming Language
[3]fmt - The Go Programming Language