Regarding performance, copying the data to a new file will most likely be the best choice.
If available disk space is an issue, you have a fun time ahead of you, because this will require some exquisite hacking skills to get fast. I think, the best can do is to allocate a large slap of buffer memory and maintain a list of holes in the file whose data resides within this buffer. Then you start by filling this buffer with everything that's out of place, starting at the beginning of the file. Once the buffer is full, you can copy data from anywhere into the hole and keep pushing data into the buffer at the end of the hole you are filling. Whenever you run out of buffer space, you will need to jump the biggest hole available and move the data that belongs there. As I said, this won't be easy, but it might be fun...