4

What is the fastest and most efficient way to prepend bytes at the beginning of a file? Basically, I want to open a file and then add a number of bytes to it. I thought of using a loop, but given that all of the bytes to prepend are the same, I don't think it would be necessary.

dnclem
  • 2,818
  • 15
  • 46
  • 64

4 Answers4

9

One approach that is not atomic wrt the file (that is, if the program dies in middle the data could be left in an inconsistent state):

  1. Open the file.
  2. Starting at the end, move the bytes backward by the additional size difference. This should be done in blocks (e.g. ReadBytes), not a byte at a time - see best way to copy between streams for an example.
  3. Fill in the new data at the start of the file.

This approach may also suffer from confusing the filesystem read-ahead scheme, however, and requires seeking / random file access. Because of these issues, I can only honestly recommend it if space on the device is an absolute premium.

Another approach that is atomic wrt the file (if the program dies any stage no data is lost and the process can be recovered):

  1. Open the old file.
  2. Create a new file.
  3. Fill data in the new file.
  4. Move data from old file to new file (once again ReadBytes) - in this case the previously linked SO question should "just work as it is".
  5. Delete old file and rename new file to old file.

The "downside" is that it requires a temporary file.

Happy coding.

Community
  • 1
  • 1
4

If you truly need to prepend, the most "secure" way is normally to write to a new file your bytes, write to this new file the old file and in the end swap the files (using for example File.Replace and using null as destinationBackupFileName.). Be aware that you'll need enough space to copy the old file!

xanatos
  • 109,618
  • 12
  • 197
  • 280
4

This is about the most succinct way I could personally think of, but doesn't avoid loops like you wanted:

int numberOfBytes = 100;
byte newByte = 0x1;

using ( var newFile = new FileStream( @"C:\newfile.dat", FileMode.CreateNew, FileAccess.Write ) )
{
    for ( var i = 0; i < numberOfBytes; i++ )
    {
        newFile.WriteByte( newByte );
    }
    using ( var oldFile = new FileStream( @"C:\oldfile.dat", FileMode.Open, FileAccess.Read ) )
    {
        oldFile.CopyTo(newFile);
    }
}

// Rename and delete files, or whatever you want to do

It could also use some error handling, but you get the idea.

Paul Walls
  • 5,884
  • 2
  • 22
  • 23
  • Writing each byte separately? Seriously? – EvAlex Mar 28 '16 at 07:49
  • "Succinct" != "the only way". You could also prepopulate an array and use `FileStream.Write` to write the whole header block. Regardless, the beauty of SO is that even on a question with an accepted answer from 4 years ago, you have the option to add your own today and include benchmark results showing the performance improvement. If it's not redundant, excessive, or convoluted, I'd even upvote it. – Paul Walls Mar 30 '16 at 23:37
0

The easiest way I could think of doing it would be to create a byte array, add in your "prepend" bytes and then convert the file you are wanting to use into another byte array and merge them together!

stuartmclark
  • 1,203
  • 13
  • 22
  • Yeah that sounds like an easy method, but it sound slow and inefficient. I was wondering if there was a better method. – dnclem Sep 03 '11 at 07:23
  • 2
    @david: It *sounds* slow? Have you tried it? Always try things which are easy first, and benchmark them to see if they're actually fast enough. – Jon Skeet Sep 03 '11 at 07:37