golang csv.write不写入但没有错误

huangapple go评论93阅读模式
英文:

golang csv.write not writing but no errors

问题

我正在尝试打开一个已存在的csv文件并向其写入数据,但是文件返回为空。这是我的代码:

file, err := os.Open("file.csv")
if err != nil {
    log.WithError(err)
}

defer file.Close()

w := csv.NewWriter(file)
defer w.Flush()

var headers = []string{"h1", "h2", "h3", "h4"}
writeHeadersErr := w.Write(headers)
if writeHeadersErr != nil {
    log.WithError(writeHeadersErr)
    file.Close()
}

我不确定如何解决这个问题,因为我没有看到任何错误被记录。

英文:

I am trying to open an existing csv file and write to it; however, the file returns empty. This is my code.

file, err := os.Open("file.csv")
	if err != nil {
		log.WithError(err)
	}

	defer file.Close()

	w := csv.NewWriter(file)
	defer w.Flush()

	var headers = []string{"h1", "h2", "h3", "h4"}
	writeHeadersErr := w.Write(headers)
	if writeHeadersErr != nil {
		log.WithError(writeHeadersErr)
		file.Close()
	}

Not sure how to approach this as I do not see any errors logged.

答案1

得分: 2

os.Open 以只读模式打开文件。你应该使用 os.OpenFile 替代:

os.OpenFile("file.csv", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)

请注意,os.Create 也可以工作,但如果文件已经存在,它会将文件截断,正如你所提到的。这可能是你想要的,也可能不是。

至于为什么你看不到错误,这是因为写入是缓冲的,实际的内容直到调用 w.Flush 才会被写入。这在 w.Write 文档中有提到:

> 写入是缓冲的,因此必须最终调用 Flush 来确保记录被写入底层的 io.Writer。

尽管你的代码中 w.Flush 本身是延迟执行的,而且无论如何都不会返回错误。你可以使用 w.Error() 来检查错误。

如果你将这两个调用放在函数的末尾,如下所示,你最终会看到错误:

    file, err := os.Open("file.csv")
    if err != nil {
        log.WithError(err)
    }
    defer file.Close()

    w := csv.NewWriter(file)
    // ... 向文件写入内容
    w.Flush()
    err = w.Error() // write file.csv: bad file descriptor

事实上,这个错误意味着你使用了错误的模式标志来打开文件。更多细节请参考:https://stackoverflow.com/questions/33851692

如果你想继续延迟执行 w.Flush(),可以将它与 w.Error() 放在一个函数字面量中,结合命名返回参数的使用,可以传播错误(如果有的话)。

例如:

func writeToCsv() (err error) {
    
    // ...打开文件
    w := csv.NewWriter(file)
    defer func() {
        w.Flush()
        err = w.Error()
    }()
    // ...函数的其余部分
}
英文:

os.Open opens a file in read-only mode. You should use os.OpenFile instead:

os.OpenFile("file.csv", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)

FYI, note that os.Create also works but it will truncate the file if it already exists, as you mention. This may or may not be what you want.

As of why you see no error, it's because writes are buffered and the content isn't actually written until you call w.Flush. This is mentioned in w.Write documentation:

> Writes are buffered, so Flush must eventually be called to ensure that the record is written to the underlying io.Writer.

Though w.Flush itself is deferred in your code, and doesn't return an error anyway. You can check for errors with w.Error().

If you place the two calls at the end of your function, as follows, you will eventually see the error:

    file, err := os.Open("file.csv")
    if err != nil {
        log.WithError(err)
    }
    defer file.Close()

    w := csv.NewWriter(file)
    // ... write to the file
    w.Flush()
    err = w.Error() // write file.csv: bad file descriptor

And as a matter of fact the error means that you opened the file with the wrong mode flags. More details in: https://stackoverflow.com/questions/33851692

If you want to keep deferring w.Flush(), place it together with w.Error() in a function literal, which if used in combination with named return params, allows you to propagate the error, if any.

For example:

func writeToCsv() (err error) {
    
    // ...open file
    w := csv.NewWriter(file)
    defer func() {
        w.Flush()
        err = w.Error()
    }()
    // ...rest of the function
}

答案2

得分: 1

你需要检查Flush()方法返回的error

w.Flush()

if err := w.Error(); err != nil {
    log.Fatal(err) // write file.csv: bad file descriptor
}

这段代码显示你正在打开一个文件进行读取而不是写入。所以要修复这个问题:

//file, err := os.Open("file.csv") // 读取文件
file, err := os.Create("file.csv") // 创建文件
if err != nil {
    log.Fatal(err)
}

https://play.golang.org/p/QhpYnrc7cmR

英文:

You need to check the error from Flush():

w.Flush()

if err := w.Error(); err != nil {
	log.Fatal(err) // write file.csv: bad file descriptor
}

which will show that you are opening a file for reading not writing. So to fix:

//file, err := os.Open("file.csv") // read file
file, err := os.Create("file.csv") // create file
if err != nil {
	log.Fatal(err)
}

https://play.golang.org/p/QhpYnrc7cmR

huangapple
  • 本文由 发表于 2021年9月20日 23:59:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/69257525.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定