我已经从json文件中的数据库中提取了我的表,现在我想读取这些文件并删除它们上的所有双引号,看起来很简单,尝试了上百种解决方案,有些解决方案将我带到内存不足的问题。我处理的文件大小超过1gb。下面的代码有一个奇怪的行为,我不明白为什么它返回空文件
public void replaceDoubleQuotes(String fileName){
log.debug(" start formatting " + fileName + " ...");
File firstFile = new File ("C:/sqlite/db/tables/" + fileName);
String oldContent = "";
String newContent = "";
BufferedReader reader = null;
BufferedWriter writer = null;
FileWriter writerFile = null;
String stringQuotes = "\\\\\\\\\"";
try {
reader = new BufferedReader(new FileReader(firstFile));
writerFile = new FileWriter("C:/sqlite/db/tables/" + fileName);
writer = new BufferedWriter(writerFile);
while (( oldContent = reader.readLine()) != null ){
newContent = oldContent.replaceAll(stringQuotes, "");
writer.write(newContent);
}
writer.flush();
writer.close();
} catch (Exception e) {
log.error(e);
}
}
当我尝试使用 FileWriter(path,true)
要在文件末尾写入程序,在硬盘满之前不要停止增加文件内存,谢谢你的帮助
ps:我也尝试过使用子字符串并附加新内容,之后虽然我写了子字符串,但也不起作用
2条答案
按热度按时间acruukt91#
热释光;博士;
不要同时读写同一个文件。
问题
代码开始读取,然后立即截断它正在读取的文件。
第一行打开文件的读取句柄。第二行打开同一文件的写入句柄。如果您查看filewriter构造函数的文档,但不使用允许您指定
append
参数,则值为false
默认情况下,也就是说,如果文件已经存在,您会立即截断它。此时(第2行)您刚刚删除了要读取的文件。所以你最终得到了一个空文件。
使用append=true怎么样
好吧,那么文件在创建时不会被删除,这是“好的”。因此,您的程序开始读取第一行,并输出(到同一个文件)过滤后的版本。
因此,每次读取一行时,都会追加另一行。
难怪您的程序永远不会到达文件的末尾:每次它前进一行,它就会创建另一行来处理。一般来说,你永远不会到达文件的结尾(当然,如果文件是一行开始,你可以,但这是一个角落的情况)。
解决方案
写一个临时文件,如果(并且只有)你成功了,然后交换文件,如果你真的需要。
此解决方案的一个优点是:如果由于任何原因进程崩溃,您将保持原始文件不变,并且可以稍后重试,这通常是一件好事。你的过程是“可重复的”。
缺点:在某个时候你需要两倍的空间(虽然您可以压缩临时文件并减少这个因素,但仍然可以。
关于内存不足问题
在处理任意大的文件时,您选择的路径(使用缓冲读写器)是正确的,因为您一次只使用一行内存。
因此,它通常可以避免内存使用问题(当然,除非您有一个没有换行符的文件,在这种情况下没有任何区别)。
其他解决方案,包括一次读取整个文件,然后在内存中执行搜索/替换,然后将内容写回,都不能很好地伸缩,因此最好避免这种计算。
不相关但重要
检查try with resources语法以正确关闭资源(reader/writer)。在这里,您忘记关闭reader,并且您没有适当地关闭writer(即:在finally子句中)。
另一件事:我敢肯定,任何一个由凡人编写的java程序都无法打败像这样的工具
sed
或者awk
在大多数unix平台上都可以使用。也许你应该检查一下用java开发自己的程序是否值得一个shell一行程序。whhtz7ly2#
@gpi已经提供了一个很好的答案,解释了为什么同时读写会导致你所经历的问题。另外值得注意的是,一次将1gb的数据读入堆中肯定会导致
OutOfMemoryError
如果没有分配足够的堆,这是可能的。要解决这个问题,你可以使用InputStream
并一次读取文件的块,然后写入另一个文件,直到过程完成,最后用修改后的文件替换现有文件并删除。使用这种方法,你甚至可以使用ForkJoinTask
因为这是一个很大的工作。旁注;也许有比这更好的解决办法
create new file, write to new file, replace existing, delete new file
.