修改 经过一番调查后,我可以用这个测试代码重现我的问题。问题与线程无关,但与快速写作无关:
public static void main(String[] args) {
String text = "Testing fast writing in file";
for (int i = 0 ; i < 100000 ; i++) {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(new File("temp.txt")));
bw.write(text);
} catch(Throwable t) { // Ensure there is no throwable for the test
System.err.println(t.getMessage());
} finally {
if(bw != null) {
try {
bw.close();
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
}
}
}
}
}
在不同的时间用Notepad ++打开,我有时候是一个空文件。 什么是避免这种情况的最佳方法?
原始问题
我正在分析一个问题,即多个线程(最多可以达到60个)使用JAXB Marshaller
在同一个文件上写入。请注意,myObject在Threads之间共享。
以下是原始代码:
Marshaller m = jaxbContext.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(myObject, myFile);
问题在于,有时当我查看文件时,它是空的(myObject永远不会为空,也不是null)。如果服务崩溃,此文件允许我们稍后恢复某些工作。
认为编组过程可能很长,我先在Buffer中写入然后写入文件:
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8192);
marshaller.marshal(myObject, outputStream);
String result = outputStream.toString();
if (result != null && !result.isEmpty()) {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(myFile));
bw.write(result);
bw.flush(); // I know close() should do that, but I tried too
} catch(IOException ioe) {
...
} finally {
... close the bw
}
问题依旧存在。所以我也尝试将synchronized
添加到方法(唯一用于写入文件的方法),但我遇到了同样的问题。
最后,我还试着让static boolean
知道我是否在写作过程中:
if (!processing) {
processing = true;
try {
Marshaller marshaller = jaxbContext.createMarshaller();
...
... close file writer
processing = false;
}
相同的行为,避免拥有空文件的最佳方法是什么?我现在有点困惑。
答案 0 :(得分:0)
我认为你错误地解释了FileWriter的使用。在所示的示例中,您在同一文件中同时使用多个线程编写,但FileWriter的工作方式是重置文件的内容,除非您明确告诉它追加。
FileWriter fw = new FileWriter(new File("temp.txt"), true);
如果您不想追加,则需要确保只有一个线程正在写入该文件。同时检查看似空的文件可能恰好恰好是在作者开始完成其工作之前文件被清除的同时。
答案 1 :(得分:0)
这是我现在带来的: 写入临时文件,一旦完成重命名。 最终文件总是填满。
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(myObject, myFileTmp);
if (myFileTmp.exists() && myFileTmp.length() > 0) {
myFile.delete();
myFileTmp.renameTo(myFile);
}
然后我修改了代码,只让一个线程写入文件。