Обновите бинарные файлы в Node.js

Я пытаюсь работать с бинарными файлами, используя 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);
    }
})

Я написал код, который берет существующий файл и пытается его прочитать. Когда я печатаю его, я получаю это в буфере:

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 ... >

Я не уверен, как преобразовать его в шестнадцатеричный, а затем попытаться изменить его ... Когда я читаю файл через онлайн-шестнадцатеричный редактор, я получаю их по 16 бит в каждой строке, и этот способ очень удобен.

Введите здесь описание изображения

У меня есть несколько вопросов:

  1. Как преобразовать из двоичного в шестнадцатеричный?
  2. Как я могу заменить данные в шестнадцатеричном файле, а затем вернуться к клиенту?
  3. Как я могу отобразить их в коде как 16-битный?
  4. Как лучше хранить их в базе данных? Хранить файл, а потом в базе хранить только путь?

Есть ли документация, которая может помочь?


person Manspof    schedule 15.02.2020    source источник


Ответы (2)


  1. Преобразование из двоичного в шестнадцатеричный:

    const file = fs.readFileSync("./test");
    const str = file.toString("hex");
    
  2. Заменить данные и вернуться к клиенту:

    let newStr = str.replace( "00", "FF" );
    let buffer = Buffer.from( newStr, "hex" );
    
  3. Отображение в 16 битах:

    for ( let i = 0; i < newStr.length; i+=16 ){
      console.log( newStr.slice( i, i+16 ) + "\n" );
    }
    
  4. Сохраните файл в доступной для записи папке загрузки и сохраните путь URL к загруженному файлу в базе данных. Это мое предложение, исходя из моего опыта. Вы можете узнать больше о том, хотите ли вы хранить изображения в базе данных (в BLOB формат) в этом сообщении Quora: Плохо ли хранить изображения в виде больших двоичных объектов в базе данных?


Вот базовая настройка, которая может вам помочь:

/тест

ABC

/app.js

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...'));

Тестовый файл содержит символы ABC. Они преобразуются в BBB, а затем загружаются.

Вы можете выбрать для вывода другой тип файла, задав соответствующее имя файла и Тип MIME (Content-Type), например. для загрузки изображения PNG:

    res.setHeader('Content-disposition', 'attachment; filename=output.png');
    res.setHeader('Content-type', 'image/png');

Примечание. для прямой двоичной обработки без промежуточного шестнадцатеричного преобразования см. Ответ Христоса Литраса.

person KostasX    schedule 15.02.2020
comment
Эй, как преобразовать строку обратно в файл и вернуть ее клиенту в виде двоичного файла? - person Manspof; 16.02.2020
comment
Вам нужно прочитать больше об этом по ссылкам ниже. Предположим, вы используете ExpressJS, поэтому эти ссылки помогут вам начать работу. Вы можете выбрать между сохранением файла и его обслуживанием или его динамическим созданием и потоковой передачей клиенту. Вы можете использовать любой тип MIME, а не только text/html или обычный, как в примерах. stackoverflow.com/ вопросы/7288814/ stackoverflow.com/questions/18467620/ gist.github.com/davidbanham/1186032 - person KostasX; 16.02.2020
comment
Для динамически сгенерированного файла: medium.com/@Shekharrajak / - person KostasX; 16.02.2020
comment
@Manspof Я обновил ответ простой настройкой, чтобы помочь вам. - person KostasX; 17.02.2020
comment
Эй, Костас, не могли бы вы объяснить, как это сделать с двоичным файлом? то, что вы пишете, для текстового/простого файла - person Manspof; 18.02.2020
comment
@Manspof Код работает с любым типом двоичного файла (даже текстовые файлы рассматриваются как двоичные в приведенном выше примере, поскольку мы переводим содержимое в шестнадцатеричные значения). Вам просто нужно выбрать соответствующий тип контента для вашего вывода. - person KostasX; 18.02.2020
comment
Вы можете просмотреть доступные типы контента (MIME) здесь: developer. mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/ - person KostasX; 18.02.2020
comment
Я сделал, как вы написали, но на стороне клиента ничего не произошло. Я ожидаю, что сервер nodejs снова отправит мне файл для загрузки. это код pastebin.com/1Bt1TPvW - person Manspof; 02.03.2020
comment
Вы получаете какие-либо ошибки (backend/frontend)? Можете ли вы опубликовать содержимое файла, который вы читаете? Как вы пытаетесь получить файл на внешнем интерфейсе? - person KostasX; 03.03.2020

Вам не нужно преобразовывать двоичные данные в шестнадцатеричные, чтобы заменить что-либо в них. Если вы хотите заменить данные внутри двоичного файла, это означает, что вы точно знаете, что хотите заменить, а это означает определенные смещения, основанные на некоторых шаблонах, структуре данных или фрагментах байтов, которые вам придется ищи.

Если вы хотите создать шестнадцатеричный онлайн-редактор для своих клиентов, то это совершенно другое дело, и оно включает в себя не только внутреннюю логику, но и пользовательский интерфейс, который позволит пользователям загружать/редактировать и скачивать файлы.

Замена двоичных данных двоичными данными с фиксированным смещением с использованием 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);

Использование 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);
}

Вы можете использовать простую логику обработки циклов и строк для печати шестнадцатеричных данных:

// 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);
  }
}

выведет что-то вроде этого:

Отображение двоичных данных Node.js в шестнадцатеричном формате

И для веб-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>

Что касается сохранения двоичных данных в базу данных, то это, конечно, зависит от типа базы данных. Большинство баз данных поддерживают тип данных Binary Large OBject (BLOB), например MySQL, и вы используете его для хранения двоичных данных. Сохранение файла в файловой системе и простое использование поля для сохранения его пути также является довольно хорошим способом, но вам придется выполнять резервное копирование/восстановление, включая те каталоги, в которых будут храниться файлы.

person Christos Lytras    schedule 18.02.2020