1

Below is my code. I am able to successfully read the file. But not able to re-write onto it with the replaced content using BufferedWriter. But can do it with ByteBuffer. Any suggestions please where I am going wrong.

myFile.txt content:

Key1-Value1
Key2-Value2
Key3-Value3

Java code below:

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 part which works:

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);
            }

The challenge is achieving the same with the help of BufferedWriter

Updated code after trying 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();
        }
raikumardipak
  • 1,461
  • 2
  • 29
  • 49
  • quick question but why arent you just using NIO? `Files.write(path, list)`. – Zabuzard Nov 24 '20 at 08:29
  • Note that your code has resource leaks because you are not using try-with-resources. – Zabuzard Nov 24 '20 at 08:30
  • `// TODO handle exception` first. `e.printStacktrace();` – Joop Eggen Nov 24 '20 at 08:57
  • @JoopEggen Done. But no exception as such. It seems that the BufferedWriter part of the code is not able to access the opened fileChannel – raikumardipak Nov 24 '20 at 09:41
  • @Zabuzard I need to take a lock on the file since there are chances that there other processes accessing the file at the same time. Files.write(path, list); throws an exception java.io.IOException: The process cannot access the file because another process has locked a portion of the file – raikumardipak Nov 24 '20 at 09:53
  • And you cant handle the lock yourself by normal means of Java synchronization? You have to have it on a per-file base? – Zabuzard Nov 24 '20 at 16:48

1 Answers1

1

You do not flush the BufferedWriter at the end, which means it contains some or all of the lines you wish to write back. Add a flush() before you close the channels to ensure the buffer is written out:

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

Ideally you should use try() with resources so that all your files are cleanly closed at appropriate time.

DuncG
  • 12,137
  • 2
  • 21
  • 33
  • Implemented your suggestions. See the question description code under heading "Updated code after trying try-with-resources" Getting a thread "main" java.nio.channels.ClosedChannelException on using try-with-resources. What I could be again doing wrong? – raikumardipak Nov 24 '20 at 17:04
  • 1
    Interesting - you are OK to move RandomAccessFile / FileChannel / FileLock into a `try()` and remove the release / close / close at end, but it looks like that you will have to leave the BufferedReader and BufferedWriter and flush() as they were because if they autoclose it messes up the channel. – DuncG Nov 24 '20 at 17:16
  • flush() is as before. Lemme try moving out BufferedReader/Writer out of try – raikumardipak Nov 24 '20 at 17:22
  • Thanks a tonne! BufferedReader/Writer moved out of try () works fine! – raikumardipak Nov 24 '20 at 17:25