简体   繁体   English

将二进制文件转换为JavaScript字符串,然后转换为Uint8Array

[英]Convert binary file to JavaScript string and then to Uint8Array

I'm trying to create a web application that can be used via a file:// URI. 我正在尝试创建一个可以通过file:// URI使用的Web应用程序。 This means that I can't use AJAX to load binary files (without turning off security features in the browser, which I don't want to do as a matter of principle). 这意味着我无法使用AJAX加载二进制文件(不关闭浏览器中的安全功能,我原本不想这样做)。

The application uses a SQLite database. 该应用程序使用SQLite数据库。 I want to provide the database to a sql.js constructor, which requires it in Uint8Array format. 我想将数据库提供给sql.js构造函数,它需要Uint8Array格式。

Since I can't use AJAX to load the database file, I could instead load it with <input type="file"> and FileReader.prototype.readAsArrayBuffer and convert the ArrayBuffer to a Uint8Array . 由于我无法使用AJAX加载数据库文件,我可以使用<input type="file">FileReader.prototype.readAsArrayBuffer加载它,并将ArrayBuffer转换为Uint8Array 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. 但是, <input type="file">需要用户交互,这很繁琐。

I thought I might be able to work around the no-AJAX limitation by using a build tool to convert my database file to a JavaScript object / string and generate a ".js" file providing the file contents, and then convert the file contents to a Uint8Array , somehow. 我想我可以通过使用构建工具将我的数据库文件转换为JavaScript对象/字符串并生成提供文件内容的“.js”文件来解决无AJAX限制,然后将文件内容转换为不知何故, 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);

In Node.js, I've tried the following: 在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');

But when I do that, I get the error "Error: database disk image is malformed". 但是,当我这样做时,我收到错误“错误:数据库磁盘映像格式错误”。

What am I doing wrong? 我究竟做错了什么? Is this even possible? 这甚至可能吗? The database disk image isn't "malformed" when I load the same file via FileReader . 当我通过FileReader加载相同的文件时,数据库磁盘映像没有“格式错误”。

Using the following code, I was able to transfer the database file's contents to the browser: 使用以下代码,我能够将数据库文件的内容传输到浏览器:

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

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. 但是, <input type="file">需要用户交互,这很繁琐。

Using current working approach would be less tedious than attempting to create workarounds. 使用当前的工作方法比尝试创建变通方法要简单得多。 If user intends to use application, user can select file from their filesystem to run application. 如果用户打算使用应用程序,用户可以从其文件系统中选择文件来运行应用程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM