You don't need to convert binary data to hexadecimal in order to replace anything in it. If you want to replace data inside a binary file, then it means that you know exactly what you want to replace, which means specific offsets based on some patterns or data structure or byte chunks you'll have to search for.
If you want to create an online hex editor for your clients, then that's a totally different thing and it involves not only backend logic, but also a UI that will let the users upload/edit and download files.
Replacing binary data with binary data on fixed offset using Buffer.copy
:
// The first three bytes of data Buffer will be replaced with 0x02 0x03 0x04 bytes
Buffer.alloc(3, new Uint8Array([0x02, 0x03, 0x04])).copy(data, 0, 0, 3);
Using Buffer.indexOf
to search for binary data patterns:
// Loading a PNG image
const data = fs.readFileSync('js-logo-16x16.png');
// Search for the PNG signature using Buffer.indexOf
const sigpos = data.indexOf(Buffer.from('PNG'));
if (sigpos >= 0) {
// If signature pos found (!= -1), replace it with JPG using Buffer.write
data.write('JPG', sigpos, 3);
}
You can use simple loop and string manipulation logic to print hexadecimal data:
// For Node.js using a Buffer
function displayHexData(data) {
for (let addr = 0; addr <= data.length; addr += 16) {
const displayAddr = addr.toString(16).toUpperCase().padStart(8, '0');
const block = data.slice(addr, Math.min(addr + 16, data.length));
let hexblock = block.toString('hex');
if (addr + 16 > data.length) {
hexblock += ' '.repeat(16 - (data.length - addr));
}
const charsblock = Array.from(block)
.map(b => b >= 32 && b <= 126 ? String.fromCharCode(b) : '.')
.join('');
console.log(displayAddr, hexblock.split(/(.{2})/).join(' '), charsblock);
}
}
will output something like this:

And for web JavaScript:
// 16 x 16 PNG 8-bit
const base64Data = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAA3NCSVQICAjb4U/gAAAAMFBMVEUAAADQvhqQghFBOgj/7iAjIAT84x+6qxdqYA3u1x2nlxT//CIxLAZKQwnOuhnZyBvQr3QtAAAACXBIWXMAAAsSAAALEgHS3X78AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAAFNJREFUCJljSIMCBlIZKW4ubmBGhkrtdTDD1Yz5rBuI4XOTyQUs4mPdEA4SSfGx3n7gCZDxKfV+24fVQEYBQyED6zQgI39d2qyVIMUpW9Kyt6UBAGorNUfBuVldAAAAAElFTkSuQmCC';
const data = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));
displayHexData(data);
function displayHexData(data) {
let result = '';
for (let addr = 0; addr <= data.length; addr += 16) {
const displayAddr = addr.toString(16).toUpperCase().padStart(8, '0');
const block = data.slice(addr, Math.min(addr + 16, data.length));
let hexblock = Array.from (block)
.map (b => b.toString(16).toUpperCase().padStart(2, "0"))
.join('');
if (addr + 16 > data.length) {
hexblock += ' '.repeat(16 - (data.length - addr));
}
const charsblock = Array.from(block)
.map(b => b >= 32 && b <= 126 ? String.fromCharCode(b) : '.')
.join('');
result += `${displayAddr} ${hexblock.split(/(.{2})/).join(' ')} ${charsblock}\n`;
}
document.getElementById('hex').appendChild(document.createTextNode(result));
}
#hex {
font-size: small;
}
<pre id="hex"></pre>
As for saving binary data to the database, it depends of course on the database type. Most databases support the Binary Large OBject (BLOB) data type, like MySQL and you use it to store binary data. Saving the file to the filesystem and just using a field to save its path is also a pretty good way to go, but you'll have to handle backups/restores, including those directories where the files will be stored.