Невозможно прочитать из недавно заблокированного файла

Итак, я пытаюсь заблокировать файл, чтобы прочитать его, но я получаю IOException, есть идеи, почему?

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


person Thang Pham    schedule 14.06.2011    source источник
comment
Разве вам не нужно использовать методы NIO для доступа к файлу после его блокировки?   -  person Jeff Foster    schedule 14.06.2011
comment
@Джефф: я не уверен. Это мой первый раз, когда я пишу файл блокировки кода.   -  person Thang Pham    schedule 14.06.2011
comment
файл открыт где-то еще (возможно, где-то в редакторе, который блокирует все, что у него открыто (как это делают инструменты M$))   -  person ratchet freak    schedule 14.06.2011
comment
@Джефф, черт возьми. Как ты мог подобрать то, о чем я не подумал. Мне нужно спать.   -  person Vineet Reynolds    schedule 14.06.2011
comment
@ Гарри, я думаю, он прав. Класс FileChannel имеет методы чтения и записи. Их использование предотвратит проблему. Использование FileReader приведет к использованию другого файлового дескриптора.   -  person Vineet Reynolds    schedule 14.06.2011
comment
@Vineet: Понятно, это может быть глупый вопрос, но мне нужно использовать здесь readLine, FileChannel только читали, возможно ли это вообще, если вы можете показать мне, как использовать FileChannel для чтения строки?   -  person Thang Pham    schedule 14.06.2011
comment
@ Гарри, тебе нужно будет прочитать из ByteBuffer, и не будет эквивалентного метода для readLine(). Вам нужно будет прочитать байты или прочитать примитивы.   -  person Vineet Reynolds    schedule 14.06.2011


Ответы (3)


Можно также добавить это как ответ вместо комментария.

Если вы используете FileLock API, вам необходимо использовать соответствующий файл API NIO.

person Jeff Foster    schedule 14.06.2011

Воспроизведение моего ответа из здесь (на случай, если он будет удален), и добавив отзыв Джеффа Фостера:

Учитывая, что выдается экземпляр исключения OverlappingFileLockException, похоже, что другой поток в том же процессе пытается заблокировать тот же файл. Это не конфликт между A и B, а скорее конфликт внутри B, если руководствоваться документацией API по методу lock() и когда условие, при котором он генерирует исключение OverlappingFileLockException:

Если блокировка, перекрывающая запрошенную область, уже удерживается этой виртуальной машиной Java, или если другой поток уже заблокирован в этом методе и пытается заблокировать перекрывающуюся область того же файла

Единственное решение для предотвращения этого состоит в том, чтобы любой другой поток в B не мог получить блокировку того же файла или той же перекрывающейся области в файле.

Выброшенный IOException имеет немного более интересное сообщение. Вероятно, это подтверждает вышеизложенную теорию, но, не глядя на весь исходный код, я ничего не могу подтвердить. Предполагается, что метод lock будет блокироваться до тех пор, пока не будет получена монопольная блокировка. Если он был получен, то не должно быть проблем с чтением из файла. Кроме одного условия. Если файл уже был открыт (и заблокирован) той же JVM в другом потоке с использованием объекта File (или, другими словами, второго/другого файлового дескриптора), то попытка чтения первого файлового дескриптора не удастся даже если блокировка была получена (в конце концов, блокировка не блокирует другие потоки).

Улучшенный дизайн будет состоять в том, чтобы иметь один поток в каждом процессе, который получает монопольную блокировку файла (при использовании одного объекта File или одного файлового дескриптора) только на определенное время, выполняя требуемые действия. активности в файле, а затем снимите блокировку.

Как указал Джефф, использование API-интерфейсов NIO, вероятно, приведет к решению проблемы. Это полностью связано с возможностью FileReader API открыть новый файловый дескриптор, который отличается от того, на который получена блокировка.

person Vineet Reynolds    schedule 14.06.2011

Возможно, вы хотите что-то вроде:

FileInputStream fis = new FileInputStream(file);
channel = fis.getChannel();
channel.lock();
bufferedReader = new BufferedReader(new InputStreamReader(fis));
person Rocky Pulley    schedule 14.06.2011
comment
Я не уверен, что этот код работает. Это было бы то, что я хочу, но у меня есть исключение, когда я делаю FileLock lock = channel.lock(). Вы можете проверить свой код? - person Thang Pham; 14.06.2011
comment
Это определенно не работает. Вы можете получить блокировки только на каналы записи. В противном случае вы получите исключение NonWriteableChannelException. - person Brian; 17.07.2014