读取1200+;Go中包含ioutil.ReadFile()的文件
我正在尝试读取目录中的所有文件(+10.000),但当我处理了大约1400个文件时,会出现“打开的文件太多”错误。我已经向垃圾收集器添加了一个显式调用,但这似乎对我的问题没有多大帮助。我检查了ioutil包的源代码,ReadFile在内部使用了读取1200+;Go中包含ioutil.ReadFile()的文件,io,go,Io,Go,我正在尝试读取目录中的所有文件(+10.000),但当我处理了大约1400个文件时,会出现“打开的文件太多”错误。我已经向垃圾收集器添加了一个显式调用,但这似乎对我的问题没有多大帮助。我检查了ioutil包的源代码,ReadFile在内部使用了defer file.Close()。那么这里出了什么问题 const TEMPLATE = `{ "source_db" : "CDARCHIEF", "doc_type" : "%s", "referentie" : "%s", "bestan
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 | %s\n", 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 | %s\n", 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 | %s\n", file.Name(), resp.Status, string(body)))
}
}
fmt.Println("\nDone!")
}
我知道大约2年前有一个类似的问题,但这对我的问题没有一个有用的答案。 < P>你可能想考虑使用。我已经成功地在10k+文件上使用了它,没有任何问题。或者,您可以深入研究源代码,看看它们在资源管理方面是否有什么不同
此外,for循环似乎有点巴洛克风格,您可以只使用整数和%
运算符
for i := 0; i < 1000000; i += 1 {
if i % 5000 == 0 {
fmt.Println(i)
}
}
i:=0的;i<1000000;i+=1{
如果i%5000==0{
fmt.Println(一)
}
}
感谢您在phihag指出这一点。在编写问题代码时,这是一个轻微的疏忽。我原来的问题仍然存在。嗯,我不能重现这个问题。当你跑步的时候,你会遇到同样的错误吗?你在哪个平台上?你确定你的REST相关代码没有创建任何文件描述符吗?你没有关闭你的resp.Body
。请参阅文档,概述中的第二个示例。啊,延迟没有帮助,因为在循环完成之前,您不会从函数返回。尝试在ioutil.ReadAll
之后的行上执行直接resp.Body.Close()
。感谢%
操作员提示。我刚开始写东西。在包装中进行过多的深度潜水使我们忽略了明显的方法。尽管错误在于没有正确关闭相应的主体。使用filepath.Walk
可以让我更快地启动和运行,因为延迟
可以工作。由于Dmitri在评论中帮助我解决了这个问题,我将把这个答案标记为已接受。有信用就有信用。