zitroneneis
zitroneneis

Reputation: 1047

Update only part of a binary file with c++

Is it possible to update only a part of a file in c++ ?

Example:

Old File A: 'A''A''A''B''B''C''C''C'
New File A: 'A''A''A''X''X''C''C''C'

as the real files are not as tiny like these examples, and I do know exactly what has changed ( offset and writeLenght for changed content ) it would be great to be able to open a file, set the stream to the right position, write the information and close the file again.... but this will lead to a file that looks like this:

Updated File: '0''0''0''X''X''C''C''C'

This is the code I used:

void update file( list<unsigned char> content, int offset){

fs::basic_ofstream< char > fileStream( path , ios::out | ios::binary );    
list< unsigned char >::const_iterator contentIter = content.begin();
// begin write operation at the offset
advance( contentIter , offset);
fileStream.seekp( offset );
while( contentIter != content.end() ){
    unsigned char value = (char)*contentIter;
    fileStream.put( value );
    ++contentIter;          
}
fileStream.close();

Is there a way to do this, or has the whole file to be rewritten everytime it changes ?

Thank you

Upvotes: 5

Views: 3748

Answers (3)

zitroneneis
zitroneneis

Reputation: 1047

Ok, thank you:
Here's a working piece of code in case anyone encounters the same question.

void update file( list<unsigned char> content, int offset, int writeLength){ 

fs::basic_fstream< char > fileStream( path , ios::out | ios::in | ios::binary );     
 list< unsigned char >::const_iterator contentIter = content.begin(); 
 // begin write operation at the offset 
 advance( contentIter , offset); 
 // set the Stream to the offset position
 fileStream.seekp( offset ); 
 while( contentIter != content.end() && writeLength != 0){ 
    unsigned char value = (char)*contentIter; 
    fileStream.put( value ); 
    ++contentIter; 
    --writeLength;          
 } 
fileStream.close(); 
}

One should check for errors or tell the stream to throw exceptions when using this code....

Upvotes: 4

Jerry Coffin
Jerry Coffin

Reputation: 490018

You have pretty much the right idea. The main thing you need to change is using an fstream instead of ofstream, and use ios::in | ios::out when you open it (assuming fs::basic_ofstream somehow resolves to std::basic_ofstream). When you open with just ios::out the existing file content is destroyed.

Edit: By the way, I have a hard time imagining a situation where using std::list<char> is a good idea. On a typical machine with 32-bit pointers and 8-bit chars, you're looking at using 8 times a much space for the pointers as you are for the data you're trying to store, and your access to the data you store is generally pretty slow as well.

Upvotes: 7

Martin Beckett
Martin Beckett

Reputation: 96119

Not as c++'ish but the obvious way to do this is with memory mapped files

Upvotes: 4

Related Questions