Go &引用;“打开的文件太多”;使用os.Create
我有大约22万个图像文件(.png)要创建。我在尝试创建第1'081个文件时遇到此错误消息: 死机:打开Go &引用;“打开的文件太多”;使用os.Create,go,Go,我有大约22万个图像文件(.png)要创建。我在尝试创建第1'081个文件时遇到此错误消息: 死机:打开/media/Snaps/pics/image1081_0.png:打开的文件太多 我添加了defer w.Close()行,但它没有更改错误 i := 1 for i <= 223129 { (some other code to prepare the data and create the chart) img := vgimg.New(450,
/media/Snaps/pics/image1081_0.png:打开的文件太多
我添加了defer w.Close()行,但它没有更改错误
i := 1
for i <= 223129 {
(some other code to prepare the data and create the chart)
img := vgimg.New(450, 600)
dc := draw.New(img)
canvases := table.Align(plots, dc)
plots[0][0].Draw(canvases[0][0])
plots[1][0].Draw(canvases[1][0])
plots[2][0].Draw(canvases[2][0])
testFile := "/media/Snaps/pics/image"+strconv.Itoa(i+60)+"_"+gain_loss+".png"
w, err := os.Create(testFile)
if err != nil {
panic(err)
}
defer w.Close()
png := vgimg.PngCanvas{Canvas: img}
if _, err := png.WriteTo(w); err != nil {
panic(err)
}
//move to next image
i = i + 1
}
i:=1
对于iok,我得到了它,将defer w.Close()
更改为w.Close()
,然后将其移动到后面
png := vgimg.PngCanvas{Canvas: img}
if _, err := png.WriteTo(w); err != nil {
panic(err)
}
我现在超过10000张图片,正在运行
“defer”语句调用其执行被延迟到的函数
由于
函数执行了一个return语句,到达
它的函数体,或者因为相应的goroutine是
惊慌失措
DeferStmt = "defer" Expression .
表达式必须是函数或方法调用;不可能
括号内。对于,对内置函数的调用受到限制
表达式语句
每次执行“defer”语句时,函数值和
调用的参数按常规计算并重新保存,但
未调用实际函数。相反,延迟函数是
在周围函数返回之前立即调用,在
相反,他们被推迟了。如果是延迟函数值
计算结果为nil,在调用函数时执行恐慌,而不是
当执行“defer”语句时
换句话说,如果在循环中处理文件,请将单个文件的处理放在单独的函数中,以将Open
与defer Close()配对。这避免了“打开的文件太多”错误
例如,使用这样的文件处理结构来保证每个文件在使用后立即关闭
package main
import (
"fmt"
"io/ioutil"
"os"
)
// process single file
func processFile(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
fmt.Println(fi.Name(), fi.Size())
return nil
}
func main() {
wd, err := os.Getwd()
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fis, err := ioutil.ReadDir(wd)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
// process all files
for _, fi := range fis {
processFile(fi.Name())
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
}
游乐场:
输出:
dev 1644
etc 1644
tmp 548
usr 822
延迟语句在周围函数返回之前不会执行,这就是为什么文件在for循环之后才保持打开状态
要解决此问题,只需在循环中插入匿名函数调用:
for ... {
func() {
w, err := os.Create(testFile)
if err != nil {
panic(err)
}
defer w.Close()
...
}()
}
这样,在循环的每次迭代之后,当前文件都将关闭。如果使用延迟
,则循环中的文件将无法工作。提供的代码不足以检查它。我已经添加了循环的开头。我应该将defer移到循环之外吗?defer
在函数返回时执行,并且在函数返回之前您将用完FD。你不能在循环外延迟(你会怎么做?),你需要关闭循环中的文件。请看,您可以将body循环移动到一个函数中,在该函数中,您可以使用原始代码中提供的defer。如果使用内联函数,请注意变量阴影(),如果之前有任何错误。关闭()文件,将不会调用Close。这就是为什么在类型上使用“延迟”来关闭事物。在您的情况下,我将简单地在循环中添加对匿名func的调用。