【发布时间】:2018-03-02 08:36:51
【问题描述】:
我有两个进程调用两个修改同一个文本文件的 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:我对Lock的理解
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
【问题讨论】:
-
@Vineet:锁定文件肯定会解决
reader - writer的问题,但我不确定writer - writer的问题。我会试着写一些代码来测试一下。 -
它会解决问题,只要您的代码事先不假设它必须在文件中的位置 X 处写入。您可以获取 FileLock,然后确定要写入的适当位置(可能在读取文件之后)。
-
@Vineet:当你锁定一个文件时,如果另一个进程进来并访问该文件,该进程会挂在那里等待锁定还是会产生IOException?
-
这取决于您在 FileChannel 上进行的调用。如果通过 API,
lock()是一个阻塞调用,而tryLock()不会阻塞。此外,这取决于所获取锁的性质。还需要考虑某些平台依赖性; FileLock 文档指出:“锁是否真正阻止另一个程序访问锁定区域的内容取决于系统,因此未指定。”。 -
@Vineet:我发现了我真正的问题,所以如果可能的话,请看看我的原始帖子(编辑部分)。我已经看了好几个小时了。 tyvm