Java:如何处理试图修改同一个文件的两个进程

Tha*_*ham 5 java io

可能的重复:
如何使用 java 锁定文件(如果可能)

我有两个进程调用两个修改相同文本文件的 Java 程序。我注意到文本文件的内容缺少数据。我怀疑当一个 java 程序获取到文本文件的写入流时,我认为它会阻止另一个 java 程序修改它(就像当你打开一个文件时,你不能删除那个文件)。除了数据库,有没有办法解决这个问题?(不是说db解决方案不干净或不优雅,只是我们在操作这个文本文件时写了很多代码)

编辑

事实证明,我针对这个问题犯了一个错误。我的文本文件中的数据丢失的原因是,

ProcessA: 继续将数据行添加到文本文件中

ProcessB: 在开始时,将文本字段的所有行加载到一个List. 然后操作该列表的包含。最后,ProcessB将列表写回,替换文本文件的包含。

这在顺序过程中效果很好。但是当一起运行时,如果ProcessA向文件中添加数据,在ProcessB操作期间List,那么当ProcessBList回时,无论ProcessA添加什么,都会被覆盖。所以我最初的想法是在ProcessBList回之前,同步文本文件和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); 
    }
}
Run Code Online (Sandbox Code Playgroud)

所以logList是当前列表ProcessB想写出来。所以在写出之前,我读取文件并将数据存储到 中tempList,如果tempListlogList不一样,同步它们。问题是,在这一点上,ProcessAProcessB当前都访问该文件,因此当我尝试锁定文件并从中读取时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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到了这个错误 IOException: The process cannot access the file because another process has locked a portion of the file

jef*_*unt 4

因此,您可以使用 Vineet Reynolds 在他的评论中建议的方法。

如果这两个进程实际上只是同一应用程序中的单独线程,那么您可以在某处设置一个标志来指示文件已打开。

如果它是两个独立的应用程序/进程,则底层文件系统应该锁定文件。当您从输出流中收到 I/O 错误时,您应该能够在该错误周围包装一个 try/catch 块,然后将您的应用程序设置为稍后重试,或者设置您的特定应用程序所需的任何行为。

文件并不是真正设计为由多个应用程序同时写入的。如果您可以描述为什么要从多个进程同时写入文件,则可能会建议其他解决方案。


最近编辑后的更新:好的,所以您至少需要 3 个文件才能完成您所说的操作。您绝对不能尝试同时读取/写入数据到单个文件。您的三个文件是:

  1. ProcessA 将新/传入数据转储到的文件
  2. ProcessB 当前正在处理的文件
  3. 保存 ProcessB 输出的最终“输出”文件。

ProcessB的循环:

  • 获取 file#2 中的任何数据,处理它,并将输出写入 file#3
  • 删除文件#2
  • 重复

ProcessA的循环:

  • 将所有新传入的数据写入 file#1
  • 定期检查 file#2 是否存在
  • 当文件#2被进程B删除时,进程A应该停止写入文件#1,将文件#1重命名为文件#2
  • 开始一个新文件#1
  • 重复