os.Create“打开的文件太多”

时间:2018-07-20 20:02:50

标签: go

我要创建约220'000个图像文件(.png)。尝试创建1'081th文件时遇到此错误消息: 恐慌:打开Scanner in = new Scanner(System.in); String input; //define arraylist outside of loop :-) ArrayList<String> arraylist1 = new ArrayList<>(); ArrayList<String> arraylist2 = new ArrayList<>(); (while in.hasNext()){ //store entire line input= in.nextLine(); //Splits input string with , stores each string in an index position in data[] String[] data = input.split(","); arraylist1.add(data[0]); arraylist2.add(data[1]); //etc.... }

我添加了defer w.Close()行,但它没有更改错误。

/media/Snaps/pics/image1081_0.png: too many open files

当然可以解决这个限制吗?也许我没有正确关闭文件?

3 个答案:

答案 0 :(得分:1)

  

The Go Programming Language Specification

     

Defer statements

     

“ defer”语句调用一个函数,该函数的执行被推迟到   周围函数返回的那一刻,要么是因为   周围的函数执行了一个return语句,到达了结尾   其功能主体,或者因为对应的goroutine是   惊慌失措。

DeferStmt = "defer" Expression .
     

表达式必须是函数或方法调用;它不可能是   括起来。内置函数的调用受到限制   表达式语句。

     

每次执行“ defer”语句时,函数值和   与往常一样评估该呼叫的参数并重新保存,但   实际功能未调用。相反,延迟函数是   在周围的函数返回之前立即调用   相反的顺序,他们被推迟了。如果延迟功能值   计算为nil,则在调用函数时执行恐慌,而不是   当执行“ defer”语句时。


换句话说,如果要循环处理文件,请将单个文件的处理放在单独的函数中,以将Opendefer 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)
        }
    }
}

游乐场:https://play.golang.org/p/FrBWqlMOzaS

输出:

dev 1644
etc 1644
tmp 548
usr 822

答案 1 :(得分:0)

直到周围的函数返回时才执行延迟语句,这就是为什么文件在for循环之后才保持打开状态的原因。

要解决此问题,您只需在循环内插入一个匿名函数调用:

for ... {
    func() {
        w, err := os.Create(testFile)
        if err != nil {
            panic(err)
        }
        defer w.Close()
        ...
    }()
}

这样,在循环的每次迭代之后,当前文件都将关闭。

答案 2 :(得分:-3)

好的,我明白了,将defer w.Close()更改为w.Close()并在

之后将其移动
png := vgimg.PngCanvas{Canvas: img}
if _, err := png.WriteTo(w); err != nil {
      panic(err)
}

我现在已经超过1万张图片并且正在运行...