Как я могу сделать действительно длинную строку, используя IndexedDB, не разбивая браузер?

Я пишу веб-приложение, которое генерирует потенциально большой текстовый файл, который пользователь будет загружать, и вся обработка выполняется в браузере. Пока что я могу читать файлы размером более 1 ГБ небольшими порциями, обрабатывать каждый порции, постепенно генерировать большой выходной файл и сохранять растущий вывод в IndexedDB. Моя более наивная попытка сохранить все результаты в памяти и затем сериализовать их в файл в самом конце приводила к сбою всех браузеров.

У меня вопрос двоякий:

  1. Могу ли я добавить запись в IndexedDB (либо строку, либо массив), не читая все это в памяти в первую очередь? Прямо сейчас это:

    task.dbInputWriteQueue.push(output);
    var transaction = db.transaction("files", "readwrite");
    var objectStore = transaction.objectStore("files");
    var request = objectStore.get(file.id);
    request.onsuccess = function()
    {
        request.results += nextPartOfOutput
        objectStore.put(request.results);
    };
    

    вызывает сбои после того, как вывод начинает становиться большим. Я мог бы просто записать несколько небольших записей в базу данных, но потом мне все равно пришлось бы потом прочитать их все в память, чтобы объединить их. Смотрите часть 2 моего вопроса...

  2. Можно ли создать URL-адрес объекта данных для ссылки на значение в IndexedDB без загрузки этого значения в память? Для небольших строк я могу сделать:

    var url = window.URL.createObjectURL(new Blob([myString]), {type: 'text/plain'});
    

    Но для больших струн это не слишком хорошо. На самом деле, он падает до загрузки строки. Кажется, что большие чтения с использованием get() из IndexedDB, по крайней мере, происходит сбой Chrome (даже происходит сбой инструментов разработчика).

Было бы быстрее, если бы я использовал Blobs вместо строк? Это преобразование дешево?

По сути, мне нужен способ, с помощью JavaScript, записать действительно большой файл на диск, не загружая все это в память в любой момент. Я знаю, что вы можете дать createObjectURL Файл, но в моем случае это не работает, так как я генерирую новый файл из файла, предоставленного пользователем.

2 ответа

Хранение BLOB-объектов будет занимать намного меньше места и ресурсов, так как больше не требуется преобразование в base64. Вы даже можете хранить "текстовые / простые" объекты в виде BLOB-объектов:

var blob = new Blob(['blob object'], {type: 'text/plain'});
var store = db.transaction(['entries'], 'readwrite').objectStore('entries');

// Store the object  
var req = store.put(blob, 'blob');
req.onerror = function(e) {
    console.log(e);
};
req.onsuccess = function(event) {
    console.log('Successfully stored a blob as Blob.');
};

Вы можете увидеть больше информации здесь: https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/

Chrome поддерживает это только с лета 2014 года: http://updates.html5rocks.com/2014/07/Blob-support-for-IndexedDB-landed-on-Chrome-Dev поэтому его нельзя использовать в более старых версиях Chrome.

Я только что снова открыл ошибку Chrome, которую отправил 2 года назад, и создал еще одну ошибку для команды FF, связанную с падением браузера при создании большого двоичного объекта. Создание больших файлов не должно быть проблемой для браузеров.

Другие вопросы по тегам