In my opinion, the approach of using a temporary file on disk is a good approach. If you are in a situation where you can create a new temporary file on disk, then nio has some options that may help you. I just walk away from the API here and the nio tutorial, but it seems that FileChannel.transferFrom or FileChannel.transferTo may be necessary tools.
I have not tested the following code, but it should point you in the right direction.
public static void main(String[] args) { int megaByte = 1024 * 1024; // prepare the paths Path inPath = Paths.get("D:/file.dat"); // java.nio.file.Paths Path outPath; // java.nio.file.Path try { outPath = Files.createTempFile(null, "swp"); // java.nio.file.Files } catch (IOException ex) { throw new IOError(ex); } // process the file try ( FileChannel readChannel = new FileChannel.open(inPath, READ); FileChannel writeChannel = new FileChannel.open(outPath, WRITE, TRUNCATE_EXISTING) ) { long readFileSize = readChannel.size(); long expectedWriteSize = readFileSize; if (readFileSize > 2 * megabyte) expectedWriteSize = readFileSize - megabyte; else if (readFileSize > megabyte) expectedWriteSize = megabyte; // copy first megabyte (or entire file if less than a megabyte) long bytesTrans = readChannel.transferTo(0, megabyte, writeChannel); // copy everything after the second megabyte if (readFileSize > 2 * megabyte) bytesTrans += readChannel.transferTo(2 * megabyte, readFileSize - 2 * megabyte, writeChannel); if (bytesTrans != expectedWriteSize) System.out.println("WARNING: Transferred " + bytesTrans + " bytes instead of " + expectedWriteSize); } catch (FileNotFoundException ex) { throw new RuntimeException("File not found!", ex); } catch (IOException ex) { throw new RuntimeException("Caught IOException", ex); } // replace the original file with the temporary file try { // ATOMIC_MOVE may cause IOException here . . . Files.move(outPath, inPath, REPLACE_EXISTING, ATOMIC_MOVE); } catch (IOException e1) { try { // . . . so it probably worth trying again without that option Files.move(outPath, inPath, REPLACE_EXISTING); } catch (IOException e2) { throw new IOError(e2); } } }
It is possible that nio will help, even if you cannot open a new file. If you open a read / write channel to a file or open two different channels in one file, one part of the file can be transferred to another part of the file using the transferTo method. I do not have enough experience to find out. The API states that a method that takes an explicit position argument (for example, the first argument of transferTo ) can continue at the same time as the operation that writes to the file, so I don't exclude this. You might want to rewrite the file into megabyte-sized chunks if you try this. If this works, then FileChannel.truncate can be used to chop the last megabyte of the file when you finish writing parts of the file to one megabyte early position in the file.
source share