0

Я пытаюсь создать веб-приложение, которое можно использовать с помощью URI file://. Это означает, что я не могу использовать AJAX для загрузки двоичных файлов (без отключения функций безопасности в браузере, что я не хочу делать в принципе).Преобразование двоичного файла в строку JavaScript, а затем в Uint8Array

Приложение использует базу данных SQLite. Я хочу предоставить базу данных конструктору sql.js, который требует его в формате Uint8Array.

Поскольку я не могу использовать AJAX для загрузки файла базы данных, я мог бы вместо того, чтобы загрузить его с <input type="file"> и FileReader.prototype.readAsArrayBuffer и преобразовать ArrayBuffer в Uint8Array. И это работает со следующим кодом:

input.addEventListener('change', function (changeEvent) { 
    var file = changeEvent.currentTarget.files[0]; 
    var reader = new FileReader(); 
    reader.addEventListener('load', function (loadEvent) { 
    var buffer = loadEvent.target.result; 
    var uint8Array = new Uint8Array(buffer); 
    var db = new sql.Database(uint8Array); 
    }); 
    reader.readAsArrayBuffer(file); 
}); 

Однако <input type="file"> требует взаимодействия с пользователем, который является утомительным.

Я думал, что смогу обойти ограничение no-AJAX с помощью инструмента построения для преобразования моего файла базы данных в объект/строку JavaScript и сгенерировать файл .js, содержащий содержимое файла, а затем конвертировать содержимое файла до Uint8Array, так или иначе.

Psuedocode:

// In Node.js: 
var fs = require('fs'); 
var sqliteDb = fs.readFileSync('path/to/sqlite.db'); 
var string = convertBufferToJsStringSomehow(sqliteDb); 
fs.writeFileSync('build/db.js', 'var dbString = "' + string + '";'); 
// In the browser (assume "build/db.js" has been loaded via a <script> tag): 
var uint8Array = convertStringToUint8ArraySomehow(dbString); 
var db = new sql.Database(uint8Array); 

В Node.js, я попробовал следующее:

var TextEncoder = require('text-encoding').TextEncoder; 
var TextDecoder = require('text-encoding').TextEncoder; 
var sql = require('sql.js'); 

var string = new TextDecoder('utf-8').decode(fs.readFileSync('path/to/sqlite.db')); 
// At this point, I would write `string` to a ".js" file, but for 
// the sake of determining if converting back to a Uint8Array 
// would work, I'll continue in Node.js... 
var uint8array = new TextEncoder().encode(string); 
var db = new sql.Database(uint8array); 
db.exec('SELECT * FROM tablename'); 

Но когда я делаю это, я получаю ошибку «Ошибка: диск базы данных изображение искажено ".

Что я делаю неправильно? Возможно ли это? Образ диска базы данных не «искажен», когда я загружаю тот же файл через FileReader.

+0

Что является результатом 'fs.readFileSync («путь/к/sqlite.db») '? – guest271314

+0

@ guest271314 В результате получается ''. – Jackson

+0

Каков результат 'string'? – guest271314

ответ

1

Используя следующий код, я был в состоянии передать содержимое файла базы данных для браузера:

// In Node.js: 
var fs = require('fs'); 
var base64 = fs.readFileSync('path/to/sqlite.db', 'base64'); 
fs.writeFileSync('build/db.js', 'var dbString = "' + base64 + '";'); 
// In the browser (assume "build/db.js" has been loaded via a <script> tag): 
function base64ToUint8Array (string) { 
    var raw = atob(string); 
    var rawLength = raw.length; 
    var array = new Uint8Array(new ArrayBuffer(rawLength)); 
    for (var i = 0; i < rawLength; i += 1) { 
    array[i] = raw.charCodeAt(i); 
    } 
    return array; 
} 
var db = new sql.Database(base64ToUint8Array(dbString)); 
console.log(db.exec('SELECT * FROM tablename')); 
+0

Что вы подразумеваете под «более прямым способом»? Если ваш ответ разрешает вопрос, вы можете принять свой собственный ответ. – guest271314

+0

Под «более прямым способом» я подразумеваю «способ, отличный от использования URL-адреса данных, который имеет более быстрое время выполнения». – Jackson

+0

_ «способ, отличный от использования URL-адреса данных, который имеет более быстрое время выполнения» _ Не верьте, что это возможно. Вы можете использовать URL-адрес «Blob», хотя это не будет сохраняться за пределами сеанса браузера. – guest271314

0

And that's working with the following code:

input.addEventListener('change', function (changeEvent) { 
    var file = changeEvent.currentTarget.files[0]; 
    var reader = new FileReader(); 
    reader.addEventListener('load', function (loadEvent) { 
    var buffer = loadEvent.target.result; 
    var uint8Array = new Uint8Array(buffer); 
    var db = new sql.Database(uint8Array); 
    }); 
    reader.readAsArrayBuffer(file); 
}); 

However, <input type="file"> requires user interaction, which is tedious.

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

+0

. Пожалуйста, перечитайте мой вопрос. Мне нужно преобразовать «sqlite.db» в строку, чтобы я мог отправить ее в браузер в файле «.js». – Jackson

+0

Is _ "И это работает со следующим кодом:" _ correct? Не знаете, как и почему результат будет другим, используя 'FileReadrer' в' nodejs'? Вы можете преобразовать строку в файл '.js', используя объекты« Blob »или« File », как показано на http://stackoverflow.com/questions/39315017/using-html-how-do-i-open-a -file-а-ан-первенствовать-файл. – guest271314

+0

Если вы считаете, что это сработает, пожалуйста, продемонстрируйте это в своем ответе. Кроме того, я добавил пример моего варианта использования в OP, см. Код в разделе «Psuedocode:». – Jackson