Adi*_*ari 1 javascript binaryfiles file node.js express
我正在尝试使用 Node.js 处理二进制文件。
我正在尝试从客户端接收二进制文件,打开二进制文件,转换为十六进制,替换数据并将新的二进制文件返回给客户端。
app.use('/read-binary-file',(req,res) => {
try {
let content = fs.readFileSync(file_path);
console.log('content', content)
res.status(200).send({content})
}
catch(err) {
console.error(err);
}
})
Run Code Online (Sandbox Code Playgroud)
我编写了采用现有文件并尝试读取它的代码。当我打印它时,我在缓冲区中得到它:
content <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >
Run Code Online (Sandbox Code Playgroud)
我不确定如何将其转换为十六进制,然后尝试更改它...当我通过在线十六进制编辑器读取文件时,我将它们每行 16 位,这种方式非常方便。
我有一些问题:
是否有任何文档可以提供帮助?
从二进制转换为十六进制:
const file = fs.readFileSync("./test");
const str = file.toString("hex");
Run Code Online (Sandbox Code Playgroud)
替换数据并返回给客户端:
let newStr = str.replace( "00", "FF" );
let buffer = Buffer.from( newStr, "hex" );
Run Code Online (Sandbox Code Playgroud)
以 16 位显示:
for ( let i = 0; i < newStr.length; i+=16 ){
console.log( newStr.slice( i, i+16 ) + "\n" );
}
Run Code Online (Sandbox Code Playgroud)
将文件存储在可写的上传文件夹中,并将上传的 URL 路径存储在数据库中。这是我的建议,根据我的经验。您可以在这篇 Quora 帖子中阅读有关是否要选择将图像存储在数据库中(以BLOB格式)的更多信息:将图像作为 blob 存储在数据库中是一种糟糕的设计吗?
以下是可能对您有所帮助的基本设置:
/测试
ABC
Run Code Online (Sandbox Code Playgroud)
/app.js
ABC
Run Code Online (Sandbox Code Playgroud)
测试文件包含字符 ABC。它们被转换为 BBB,然后下载。
您可以选择输出不同的文件类型,通过设置适当的文件名和MIME 类型(内容类型),例如下载PNG图像:
const express = require('express');
const app = express();
const fs = require('fs');
app.use("/test", (req, res) => {
const file = fs.readFileSync("./test"); // Read file as binary
const str = file.toString("hex"); // Convert to hexadecimal
let newStr = str.replace(/41|43/g, "42"); // Replace hexadecimal characters
let buffer = Buffer.from(newStr, "hex"); // Create buffer from hexadecimal
// Send to the user as download
res.setHeader('Content-disposition', 'attachment; filename=test-edited.txt');
res.setHeader('Content-type', 'text/plain');
res.charset = 'UTF-8';
res.write(buffer);
res.end();
});
app.listen(3000, () => console.log('Server Running...'));
Run Code Online (Sandbox Code Playgroud)
注意:对于没有中间十六进制转换的直接二进制操作,请参阅Christos Lytras 的回答。
您不需要将二进制数据转换为十六进制来替换其中的任何内容。如果您想替换二进制文件中的数据,则意味着您确切地知道要替换的内容,这意味着基于某些模式或数据结构或您必须搜索的字节块的特定偏移量。
如果您想为您的客户创建一个在线十六进制编辑器,那么这是完全不同的事情,它不仅涉及后端逻辑,还涉及一个允许用户上传/编辑和下载文件的 UI。
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);
Run Code Online (Sandbox Code Playgroud)
Buffer.indexOf搜索二进制数据模式:// 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);
}
Run Code Online (Sandbox Code Playgroud)
// 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);
}
}
Run Code Online (Sandbox Code Playgroud)
将输出如下内容:
// 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));
}Run Code Online (Sandbox Code Playgroud)
#hex {
font-size: small;
}Run Code Online (Sandbox Code Playgroud)
<pre id="hex"></pre>Run Code Online (Sandbox Code Playgroud)
至于将二进制数据保存到数据库中,当然取决于数据库类型。大多数数据库都支持二进制大对象(BLOB) 数据类型,例如MySQL,您可以使用它来存储二进制数据。将文件保存到文件系统并仅使用字段来保存其路径也是一种不错的方法,但您必须处理备份/恢复,包括将存储文件的那些目录。