英文:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论