In a Java program, I need to exchange files in a large ZIP file quickly.
So if a.txt is a file inside b.zip I want to replace the a.txt with a new version of a.txt inside b.zip. It should happen in a second or less.
I wonder if the following would be possible:
This would leave some "garbage" lying around (as in the contents of the old a.txt file, which does not really matter), but one would not need to copy the whole ZIP file.
Alternatively, if you cannot just remove the file, one could move it to some directory like garbage/a.txt, which is then ignored by the program reading the ZIP file.
Can this be done (within Java)?
Yes, this is possible, but you would need to somehow mark the old version of a.txt as garbage, renaming it to something else. You can also replace its contents with garbage, if that's helpful somehow. The total space taken by the local header and the data, and data descriptor if present, would need to remain exactly the same, so the new path name would need to be the same length or shorter (e.g. making the data longer). You could change the compression method, e.g. making it stored, if you want to change the data. That would make it easier to match the length. Then you'd need to update the lengths and CRC in the local header or data descriptor for the new data.
You could also remove the the old a.txt from the central directory. I recommend that you do. Then nearly all unzippers will never see it. A streaming unzipper will still see that entry. Streaming unzippers are rarely used though. If you are in control of the application at the other end, you could just make sure that one isn't.
For the streaming unzippers, you could make the path name length zero. Then the unzipper can't save it. (I think. Does any file system permit a zero-length name? Linux, Windows, and macOS don't at least.) I'm not sure how all streaming unzippers will handle that, but if they error out, at least you're likely to hear about it!
To implement any of this, you will need to write your own code to parse the zip file format to do this kind of finagling. This includes dealing with the Zip64 extensions and with data descriptors that follow the data. I can provide assistance if you need to come back here with new questions. Adding a new entry at the end is straightforward, but make sure the central directory offset and length is updated in the end records.
Note: I have provided example code in other answers here.