使用ioutil读取1200多个文件时出错.Go中的ReadFile()



我正在尝试读取目录中的所有文件(+10.000),但当我处理了大约1400个文件时,我遇到了"打开的文件太多"错误。我添加了一个对垃圾收集器的显式调用,但这似乎并不能解决我的问题。我检查了ioutil包的源代码,ReadFile在内部使用defer file.Close()(正如预期的那样)。那么,这里出了什么问题?

    const TEMPLATE = `{ "source_db" : "CDARCHIEF", "doc_type" : "%s", "referentie" : "%s", "bestandsnaam" : "%s", "tekst" : "%s" }`
const MAPPING = `{ ... }`
var DIR, DOCTYPE, URL string
func init() {
    flag.StringVar(&DIR, "d", "./", "de directory met de ge-ocrde bestanden")
    flag.StringVar(&DOCTYPE, "t", "AG", "document type [ AG, CO, NN ]")
    flag.StringVar(&URL, "url", "...", "url voor de juiste index")
}
func main() {
    flag.Parse()
    fmt.Println("CD Archive Importer")
    importDocuments()
}
func importDocuments() {
    logfile, _ := os.Create("./importer.log")
    defer logfile.Close()
    files, _ := ioutil.ReadDir(DIR)
    error_counter := 0
    for i, file := range files {
        if math.Mod(float64(i), 400.0) == 0.0 {
            runtime.GC()
            fmt.Println("Running garbage collector")
        }
        fmt.Printf("Importing ( %d / %d ) [ errors: %d ]r", i+1, len(files), error_counter)
        contents, err := ioutil.ReadFile(DIR + "/" + file.Name())
        if err != nil {
            error_counter = error_counter + 1
            logfile.WriteString(fmt.Sprintf("[ERROR/IO] : %s | %sn", file.Name(), err))
            continue
        }
        contents_string := strings.Replace(string(contents), "n", " ", -1)
        contents_string = strings.Replace(contents_string, """, " ", -1)
        contents_string = strings.Replace(contents_string, "\", " ", -1)
        referentie := strings.Trim(file.Name(), ".txt")
        message := strings.NewReader(fmt.Sprintf(TEMPLATE, DOCTYPE, referentie, file.Name(), contents_string))
        resp, error := http.Post(URL, "application/json", message)
        if error != nil {
            error_counter = error_counter + 1
            logfile.WriteString(fmt.Sprintf("[ERROR/NET] : %s | %s | %sn", file.Name(), resp.Status, error))
            continue
        }
            defer resp.Body.Close()
        if resp.StatusCode != 201 {
            body, _ := ioutil.ReadAll(resp.Body)
            error_counter = error_counter + 1
            logfile.WriteString(fmt.Sprintf("[ERROR/ES] : %s | %s | %sn", file.Name(), resp.Status, string(body)))
        }
    }
    fmt.Println("nDone!")
}

我知道大约两年前有一个类似的问题,但对我的问题没有一个有用的答案。

您可能需要考虑使用filepath。步行我已经成功地在10k以上的文件上使用了它,没有遇到任何问题。或者,你可以深入研究源代码,看看他们在资源管理方面是否有什么不同。

此外,for循环似乎有点巴洛克风格,您可以只使用整数和%运算符。

for i := 0; i < 1000000; i += 1 {
    if i % 5000 == 0 {
        fmt.Println(i)
    }
}

相关内容

最新更新