io Java:如何处理试图修改同一文件的两个进程
Possible Duplicate:
How can I lock a file using java (if possible)
我有两个进程,调用修改同一文本文件的两个Java程序。我注意到文本文件的内容缺少数据。我怀疑当一个java程序获得文本文件的写入流时,它会阻止另一个java程序对其进行修改(就像打开一个文件时,不能删除该文件)。除了数据库之外,还有其他解决方法吗?(并不是说db解决方案不干净也不优雅,只是我们在处理这个文本文件时编写了很多代码)
编辑
事实证明,我针对问题犯了一个错误。我的文本文件中的数据丢失的原因是
ProcessA
:保持将数据行添加到文本文件
ProcessB
:开始时,将文本字段的所有行加载到List
中。然后操作该列表的内容。最后,ProcessB
将列表写回,替换文本文件的内容
这在顺序过程中非常有效。但是当一起运行时,如果ProcessA
在ProcessB
操作List
期间向文件添加数据,那么当ProcessB
写回List
时,不管ProcessA
刚刚添加的是什么,都将被覆盖。所以我最初的想法是在ProcessB
写List
之前,在文本文件和List
之间同步数据。因此,当我写回List
时,它将包含所有内容。这就是我的努力
public void synchronizeFile(){
try {
File file = new File("path/to/file/that/both/A/and/B/write/to");
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
FileLock lock = channel.lock(); //Lock the file. Block until release the lock
List<PackageLog> tempList = readAllLogs(file);
if(tempList.size() > logList.size()){
//data are in corrupted state. Synchronized them.
for(PackageLog pl : tempList){
if(!pl.equals(lookUp(pl.getPackageLabel().getPackageId(), pl.getPackageLabel().getTransactionId()))){
logList.add(pl);
}
}
}
lock.release(); //Release the file
channel.close();
} catch (IOException e) {
logger.error("IOException: ", e);
}
}
所以logList
是ProcessB
想要写出的当前列表。因此,在写之前,我读取文件并将数据存储到tempList
,如果tempList
和logList
不相同,请同步它们。问题是在这一点上,ProcessA
和ProcessB
当前都在访问该文件,因此当我试图锁定该文件并从中读取List<PackageLog> tempList = readAllLogs(file);
时,我要么得到OverlappingFileLockException
,要么得到java.io.IOException: The process cannot access the file because another process has locked a portion of the file
。请帮助我解决此问题:(
EDIT2:我对锁的理解
public static void main(String[] args){
File file = new File("C:\\dev\\harry\\data.txt");
FileReader fileReader = null;
BufferedReader bufferedReader = null;
FileChannel channel = null;
FileLock lock = null;
try{
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.lock();
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
String data;
while((data = bufferedReader.readLine()) != null){
System.out.println(data);
}
}catch(IOException e){
e.printStackTrace();
}finally{
try {
lock.release();
channel.close();
if(bufferedReader != null) bufferedReader.close();
if(fileReader != null) fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我得到了这个错误IOException: The process cannot access the file because another process has locked a portion of the file
# 1 楼答案
更新问题中的代码很可能是进程B的代码,而不是进程A的代码。我假设情况就是这样
考虑到抛出了
OverlappingFileLockException
异常的一个实例,同一进程中的另一个线程似乎正在尝试锁定同一文件。这不是a和B之间的冲突,而是B内部的冲突,如果查看lock()方法上的API文档,并且当它抛出OverlappingFileLockException时:防止这种情况的唯一解决方案是阻止B中的任何其他线程获取同一文件或文件中相同重叠区域的锁
抛出的
IOException
有一个更有趣的消息。它可能证实了上述理论,但如果不看完整的源代码,我无法证实任何事情。lock
方法将被阻塞,直到获得独占锁。如果它是被收购的,那么写入文件应该没有问题。除了一个条件。如果文件已经被不同线程中的同一JVM使用文件对象(或者换句话说,第二个/不同的文件描述符)打开(并锁定),那么即使获得了锁,尝试写入第一个文件描述符的操作也会失败(毕竟,锁不会锁定其他线程)一种改进的设计是,在每个进程中都有一个线程,该线程仅在一段时间内(使用单个文件对象或单个文件描述符)获取文件的独占锁,在文件中执行所需的活动,然后释放锁
# 2 楼答案
所以,你可以使用维尼特·雷诺兹在评论中建议的方法
如果这两个进程实际上只是同一个应用程序中的独立线程,那么可以在某个地方设置一个标志来指示文件已打开
如果是两个单独的应用程序/进程,底层文件系统应该锁定这些文件。当您的输出流出现I/O错误时,您应该能够围绕该错误包装一个try/catch块,然后将您的应用程序设置为稍后重试,或者设置您的特定应用程序所需的任何行为
文件并不是真正设计成由多个应用程序同时写入的。如果您可以描述为什么要从多个进程同时写入一个文件,可能还有其他解决方案可以建议
最近编辑后的更新: 好的,所以你至少需要3个文件来完成你所说的。您绝对不能尝试同时向单个文件读/写数据。你的三个文件是:
ProcessB的循环:
ProcessA循环:
# 3 楼答案
使用MapReduce思维来思考这个问题。假设每个程序都在写输出,而不读取另一个程序的输出。我会写两个独立的文件,然后有一个“减少”阶段。您的缩减可能是一个简单的按时间顺序排列的合并
但是,如果您的程序“需要彼此的输出”。你有一个完全不同的问题,需要重新思考如何划分工作
最后,如果两个程序的输出是相似但独立的,并且将其写入一个文件,以便第三个程序可以读取所有这些文件,请考虑改变第三个程序来读取两个文件。p>
# 4 楼答案
如果这是两个独立的应用程序试图访问该文件。那个人会通过IOException,因为他无法访问它。如果出现这种情况,请在
catch(IOException err){}
中添加代码,将当前线程暂停几毫秒,然后递归尝试再次写入,直到它获得访问权限这将继续尝试,直到你得到一个
StackOverflow Exception
意味着它进入太深;但在这种情况下发生这种情况的可能性很小——只有当文件被其他应用程序长时间打开时才会发生希望这有帮助