Почему BufferedWriter не выполняет запись в файл по открытому файловому каналу?

#java #nio #bufferedwriter #filechannel #java.nio.file

#java #nio #bufferedwriter #filechannel #java.nio.file

Вопрос:

Ниже приведен мой код. Я могу успешно прочитать файл. Но не может выполнить повторную запись в него с замененным содержимым с помощью BufferedWriter. Но можно сделать это с помощью ByteBuffer. Любые предложения, пожалуйста, где я ошибаюсь.

myFile.txt содержание:

 Key1-Value1
Key2-Value2
Key3-Value3
 

Код Java ниже:

 String fileAbsolutePath = "C:\myPath\myFile.txt";

        try {
            RandomAccessFile file = new RandomAccessFile(fileAbsolutePath, "rw");
            FileChannel fileChannel = file.getChannel();
            FileLock lock = fileChannel.lock();
            // read from the channel
            BufferedReader bufferedReader = new BufferedReader(Channels.newReader(fileChannel, "UTF-8"));
        List<String> filteredList = bufferedReader.lines().filter(line -> !line.contains("KEY1-VALUE1")).onClose(() -> {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw new UncheckedIOException(ex);
            }
        }).collect(Collectors.toList());
            fileChannel.truncate(0);
            BufferedWriter bufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, "UTF-8"));
            for (String string : list) {
                bufferedWriter.write(string);//does n't work
                bufferedWriter.newLine();
            }
            lock.release();
            file.close();
            fileChannel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
 

Часть ByteBuffer, которая работает:

 ByteBuffer buff = null;
            for (int i = 0; i < filteredList.size(); i  ) {
                buff = ByteBuffer.wrap(filteredList.get(i).concat("n").getBytes(StandardCharsets.UTF_8));
                fileChannel.write(buff);
            }
 

Задача заключается в достижении того же с помощью BufferedWriter

Обновленный код после попытки try-with-resources

 try (RandomAccessFile file = new RandomAccessFile(fileAbsolutePath, "rw");
                FileChannel fileChannel = file.getChannel();
                FileLock lock = fileChannel.lock();
                BufferedReader bufferedReader = new BufferedReader(Channels.newReader(fileChannel, "UTF-8"));
                BufferedWriter bufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, "UTF-8"))) {

            // read from the channel
            List<String> list = bufferedReader.lines().filter(line -> !line.contains("Key1-Value1"))
                    .collect(Collectors.toList());
            fileChannel.truncate(0);
            list.forEach(item -> {
                try {
                    bufferedWriter.write(item.concat("n"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            bufferedWriter.flush();
        }
 

Комментарии:

1. быстрый вопрос, но почему вы просто не используете NIO ? Files.write(path, list) .

2. Обратите внимание, что в вашем коде есть утечки ресурсов, потому что вы не используете try-with-resources .

3. // TODO handle exception Первый. e.printStacktrace();

4. @JoopEggen Готово. Но исключения как такового нет. Похоже, что часть кода BufferedWriter не может получить доступ к открытому файловому каналу

5. @Zabuzard Мне нужно заблокировать файл, поскольку есть вероятность, что другие процессы одновременно обращаются к файлу. Files.write(путь, список); выдает исключение java.io.IOException: процесс не может получить доступ к файлу, поскольку другой процесс заблокировал часть файла

Ответ №1:

Вы не очищаете BufferedWriter в конце, что означает, что он содержит некоторые или все строки, которые вы хотите записать обратно. Добавьте flush() перед закрытием каналов, чтобы убедиться, что буфер записан:

 bufferedWriter.flush();
lock.release();
 

В идеале вы должны использовать try() with resources, чтобы все ваши файлы были аккуратно закрыты в соответствующее время.

Комментарии:

1. Реализованы ваши предложения. Смотрите Код описания вопроса под заголовком «Обновленный код после попытки try-with-resources», получая поток «main» java.nio.channels. Исключение ClosedChannelException при использовании try-with-resources. Что я мог снова делать неправильно?

2. Интересно — вы можете переместить RandomAccessFile / FileChannel / FileLock в a try() и удалить release / close / close в конце, но, похоже, вам придется оставить BufferedReader и BufferedWriter и flush() такими, какими они были, потому что, если они автоматически закрываются, это портит канал.

3. flush() работает как и раньше. Давайте попробуем вывести BufferedReader / Writer из try

4. Огромное спасибо! BufferedReader / Writer, перемещенный из try (), работает нормально!