Актуализирайте двоични файлове в 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 тип желаете, не само текст/html или обикновен, както в примерите. stackoverflow.com/ questions/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
Хей kostas, можеш ли да обясниш как да го направя с двоичен файл? това, което пишете е за текстов/обикновен файл - 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