Я хотел бы отменить следующие шаги, выполненные на клиенте в javascript, но у меня проблемы с большим двоичным объектом.
В базе данных indexedDB над открытым курсором в индексе хранилища объектов:
- Извлеченный объект данных из базы данных.
- Преобразованный объект в строку с помощью JSON.stringify.
- Создан новый большой двоичный объект { type: 'text/csv' } из строки JSON.
- Записал большой двоичный объект в массив.
- Переместил курсор вниз на единицу и повторил с шага 1.
После успешного завершения транзакции из массива больших двоичных объектов был создан новый большой двоичный объект того же типа.
Причина этого заключается в том, что конкатенация строк JSON превысила максимально допустимый размер для одной строки; поэтому не удалось сначала объединить и создать один блок этой большой строки. Однако массив BLOB-объектов можно объединить в один BLOB-объект большего размера, примерно 350 МБ, и загрузить его на диск клиента.
Чтобы обратить этот процесс вспять, я подумал, что могу прочитать большой двоичный объект, а затем разрезать его на составные двоичные объекты, а затем прочитать каждый двоичный объект как строку; но я не могу понять, как это сделать.
Если FileReader читается как текст, результатом является один большой блок текста, который нельзя записать в одну переменную, поскольку он превышает максимальный размер и вызывает ошибку переполнения размера выделения.
Оказалось, что чтение файла как буфера массива будет подходом, позволяющим разрезать большой двоичный объект на части, но, похоже, существует какая-то проблема с кодировкой.
Есть ли способ отменить исходный процесс как есть или добавить шаг кодирования, который позволит преобразовать буфер массива обратно в исходные строки?
Я попытался прочитать некоторые вопросы, которые казались связанными, но на данный момент я не понимаю проблемы кодирования, которые они обсуждали. Кажется, что восстановить строку довольно сложно.
Спасибо за любые рекомендации, которые вы можете предоставить.
Дополнительная информация после использования принятого ответа
Конечно, в моем коде, опубликованном ниже, нет ничего особенного, но я решил поделиться им с теми, кто может быть таким же новичком в этом, как и я. Это принятый ответ, интегрированный в функцию asnyc, используемую для чтения больших двоичных объектов, их анализа и записи в базу данных.
Этот метод использует очень мало памяти. Жаль, что нет способа сделать то же самое для записи данных на диск. При записи базы данных на диск использование памяти увеличивается по мере создания большого двоичного объекта, который затем освобождается вскоре после завершения загрузки. Использование этого метода для загрузки файла с локального диска, по-видимому, работает без загрузки всего большого двоичного объекта в память перед нарезкой. Как будто файл читается с диска по кусочкам. Таким образом, это очень эффективно с точки зрения использования памяти.
В моем конкретном случае еще многое предстоит сделать, потому что использование этого для записи 50 000 строк JSON общим объемом 350 МБ обратно в базу данных довольно медленно и занимает около 7:30.
Сейчас каждая отдельная строка разделяется отдельно, читается как текст и записывается в базу данных за одну транзакцию. Будет ли разделение большого двоичного объекта на более крупные части, состоящие из набора строк JSON, чтение их в виде текста в блоке, а затем запись их в базу данных в одной транзакции, выполняться быстрее, при этом не используя большой объем памяти? Мне нужно будет поэкспериментировать и тема для отдельного вопроса.
Если использовать альтернативный цикл, который определяет количество строк JSON, необходимых для заполнения размера const c, а затем нарезать большой двоичный объект этого размера, прочитать его как текст и разделить на части для анализа каждой отдельной строки JSON, время для завершения составит около 1 :30 для c = от 250 000 до 1 000 000. Похоже, что синтаксический анализ большого количества строк JSON все равно замедляет работу. Большие фрагменты больших двоичных объектов не преобразуются в большие объемы текста, анализируемые как единый блок, и каждую из 50 000 строк необходимо анализировать отдельно.
try
{
let i, l, b, result, map, p;
const c = 1000000;
// First get the file map from front of blob/file.
// Read first ten characters to get length of map JSON string.
b = new Blob( [ f.slice(0,10) ], { type: 'text/csv' } );
result = await read_file( b );
l = parseInt(result.value);
// Read the map string and parse to array of objects.
b = new Blob( [ f.slice( 10, 10 + l) ], { type: 'text/csv' } );
result = await read_file( b );
map = JSON.parse(result.value);
l = map.length;
p = 10 + result.value.length;
// Using this loop taks about 7:30 to complete.
for ( i = 1; i < l; i++ )
{
b = new Blob( [ f.slice( p, p + map[i].l ) ], { type: 'text/csv' } );
result = await read_file( b ); // FileReader wrapped in a promise.
result = await write_qst( JSON.parse( result.value ) ); // Database transaction wrapped in a promise.
p = p + map[i].l;
$("#msg").text( result );
}; // next i
$("#msg").text( "Successfully wrote all data to the database." );
i = l = b = result = map = p = null;
}
catch(e)
{
alert( "error " + e );
}
finally
{
f = null;
}
/*
// Alternative loop that completes in about 1:30 versus 7:30 for above loop.
for ( i = 1; i < l; i++ )
{
let status = false,
k, j, n = 0, x = 0,
L = map[i].l,
a_parse = [];
if ( L < c ) status = true;
while ( status )
{
if ( i+1 < l && L + map[i+1].l <= c )
{
L = L + map[i+1].l;
i = i + 1;
n = n + 1;
}
else
{
status = false;
};
}; // loop while
b = new Blob( [ f.slice( p, p + L ) ], { type: 'text/csv' } );
result = await read_file( b );
j = i - n;
for ( k = j; k <= i; k++ )
{
a_parse.push( JSON.parse( result.value.substring( x, x + map[k].l ) ) );
x = x + map[k].l;
}; // next k
result = await write_qst_grp( a_parse, i + ' of ' + l );
p = p + L;
$("#msg").text( result );
}; // next i
*/
/*
// Was using this loop when thought the concern may be that the JSON strings were too large,
// but then realized the issue in my case is the opposite one of having 50,000 JSON strings of smaller size.
for ( i = 1; i < l; i++ )
{
let x,
m = map[i].l,
str = [];
while ( m > 0 )
{
x = Math.min( m, c );
m = m - c;
b = new Blob( [ f.slice( p, p + x ) ], { type: 'text/csv' } );
result = await read_file( b );
str.push( result.value );
p = p + x;
}; // loop while
result = await write_qst( JSON.parse( str.join("") ) );
$("#msg").text( result );
str = null;
}; // next i
*/