Function Repository Resource:

BinaryWriteAt

Source Notebook

Overwrite part of a file with binary data

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["BinaryWriteAt"][path,bytes,offset]

writes bytes to path beginning at the position given by offset.

ResourceFunction["BinaryWriteAt"][path,bytes]

uses an offset of zero.

Details and Options

The value for path can be any of the following:
"file"a string corresponding to a local file path
File["file"]a local file path
The value for bytes can be any of the following:
"str"a string
ByteArray[]a byte array
{b1,b2,}a sequence of byte values given as integers
Negative values for offset can be given to specify an offset from the end of the file.
ResourceFunction["BinaryWriteAt"] accepts the CharacterEncoding option, which specifies how strings should be converted to byte values before writing.
The CharacterEncoding option has no effect if bytes is not a string.

Examples

Basic Examples (3) 

Create a test file:

In[1]:=
file = Export[CreateFile[], ConstantArray[37, 50], "Binary"];
ReadString[file]
Out[1]=

Overwrite the first few bytes of the file with new data:

In[2]:=
ResourceFunction["BinaryWriteAt"][file, "hello world"];
ReadString[file]
Out[2]=

Overwrite a different part of the file:

In[3]:=
ResourceFunction["BinaryWriteAt"][file, "everyone", 6];
ReadString[file]
Out[3]=
In[4]:=
ResourceFunction["BinaryWriteAt"][file, "goodbye", -10];
ReadString[file]
Out[4]=
In[5]:=
DeleteFile[file]

Scope (2) 

Use a negative value to specify an offset from the end of the file:

In[6]:=
file = Export[CreateFile[], "0123456789", "String"];
In[7]:=
ResourceFunction["BinaryWriteAt"][file, "appended", -1];
ReadString[file]
Out[7]=
In[8]:=
DeleteFile[file]

Use UpTo to avoid out-of-range errors:

In[9]:=
file = Export[CreateFile[], "0123456789", "String"];
In[10]:=
ResourceFunction["BinaryWriteAt"][file, "out of range", 100]
Out[10]=
In[11]:=
ResourceFunction["BinaryWriteAt"][file, "out of range", UpTo[100]]
Out[11]=
In[12]:=
ReadString[file]
Out[12]=
In[13]:=
DeleteFile[file]

Options (4) 

CharacterEncoding (4) 

Create a test file with "ISO8859-7" character encoding:

In[14]:=
ba = StringToByteArray[
   "\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]\[Alpha]", "ISO8859-7"];
file = Export[CreateFile[], ba, "Binary"];

By default, BinaryWriteAt uses "UTF-8" encoding when writing strings:

In[15]:=
ResourceFunction["BinaryWriteAt"][file, "\[Beta]", 5];
ByteArrayToString[ReadByteArray[file], "ISO8859-7"]
Out[15]=

Reset the test file:

In[16]:=
Export[file, ba, "Binary"];

Specify an alternate encoding to write the correct bytes:

In[17]:=
ResourceFunction["BinaryWriteAt"][file, "\[Beta]", 5, CharacterEncoding -> "ISO8859-7"];
ByteArrayToString[ReadByteArray[file], "ISO8859-7"]
Out[17]=
In[18]:=
DeleteFile[file]

Applications (1) 

Modify one value in a data file:

In[19]:=
tmp = Export[CreateFile[], Identity[ByteArray][CompressedData["
1:eJwdkElOA0EMRcOSPkVzAeR5WDNs2HGDDvQiUpJGUUvAbTgqdm2sL9cr/28/
HLf3493hcPir8vKzXL7O6/x66rLdLss+Pd3WZV8/5+Pv/LZep+dlX+aP7bov
p2t31/P2PcGjs4blPTyaYbKWYDYxL0GmBlSMCYZSdVSMCUt4pkD/chT2KCbR
cTCuxNmCiMUbBiJJLUZBwKW9xMKivQidG5aoie1Fnkg53EWT+4m8ojWcYSzF
QIggjzmENASyRTPILtB5FMO8O1FbSIxgjtx5LDgIminvEVUMQKFEqtlgQhGw
mQCqHXsypUWfpS6W2sK0NrPOQ2bjYihYd+iBEqRtWtUJp3+yk1cz
"]], "Binary"];
ReadString[tmp]
Out[19]=
In[20]:=
ResourceFunction["BinaryWriteAt"][tmp, "1.234567", 56]
Out[20]=
In[21]:=
ReadString[tmp]
Out[21]=
In[22]:=
DeleteFile[tmp]

Properties and Relations (5) 

Create a huge test file:

In[23]:=
huge = ResourceFunction["CreateRandomFile"][5000000000];
FileSize[huge]
Out[23]=

BinaryWriteAt can efficiently modify bytes without needing to read the entire file:

In[24]:=
AbsoluteTiming[
 MaxMemoryUsed[
  ResourceFunction["BinaryWriteAt"][huge, ConstantArray[0, 10], 0]]]
Out[24]=

Check the first few bytes:

In[25]:=
BinaryReadList[huge, "Byte", 15]
Out[25]=

The performance is not dependent on the file position:

In[26]:=
AbsoluteTiming[
 MaxMemoryUsed[
  ResourceFunction["BinaryWriteAt"][huge, ConstantArray[0, 10], -11]]]
Out[26]=

Check the last few bytes:

In[27]:=
stream = OpenRead[huge, BinaryFormat -> True];
SetStreamPosition[stream, FileByteCount[huge] - 15];
BinaryReadList[stream, "Byte", 20]
Out[27]=
In[28]:=
Close[stream];
DeleteFile[huge];

Version History

  • 1.0.0 – 13 December 2021

Related Resources

License Information