Производительность JavaScript FileReader Slice

Я пытаюсь получить доступ к первым нескольким строкам текстовых файлов с помощью FileApi в JavaScript.

Для этого я нарезаю произвольное количество байтов от начала файла и передаю большой двоичный объект FileReader.

Для больших файлов это занимает очень много времени, хотя, насколько я понимаю, требуется доступ только к первым нескольким байтам файла. Есть ли какая-то реализация в фоновом режиме, которая требует доступа ко всему файлу, прежде чем его можно будет разрезать? Зависит ли это от реализации FileApi в браузере? В настоящее время я тестировал как Chrome, так и Edge (хром).

Анализ в Chrome с использованием инструментов разработки производительности показывает, что перед читателем отключается загрузка и не увеличивается использование оперативной памяти. Однако это может быть связано с тем, что FileApi реализован в самом браузере и не отражается в статистике производительности JavaScript.

Моя реализация FileReader выглядит примерно так:

const reader = new FileReader();

reader.onloadend = (evt) => {
  if (evt.target.readyState == FileReader.DONE) {
    console.log(evt.target.result.toString());
  }
};

// Slice first 10240 bytes of the file
var blob = files.item(0).slice(0, 1024 * 10);

// Start reading the sliced blob
reader.readAsBinaryString(blob);

Он работает нормально, но, как описано, работает не очень хорошо для больших файлов. Я пробовал на 10кб, 100мб и 6гб. Время до регистрации первых 10 Кбайт, по-видимому, напрямую коррелирует с размером файла.

Есть ли у вас какие-либо предложения по повышению производительности чтения начала файла?


Изменить: использование потоков Response и DOM, предложенных @BenjaminGruenbaum, к сожалению, не улучшает производительность чтения.

var dest = newWritableStream({​​​​​​​​
    write(str) {​​​​​​​​
        console.log(str);
    }​​​​​​​​,
}​​​​​​​​);
var blob = files.item(0).slice(0, 1024 * 10);

(blob.stream ? blob.stream() : newResponse(blob).body)
// Decode the binary-encoded response to string
  .pipeThrough(newTextDecoderStream())
  .pipeTo(dest)
  .then(() => {​​​​​​​​
      console.log('done');
  }​​​​​​​​);


person kacase    schedule 17.02.2021    source источник
comment
Привет, помогает ли использование Response и потоков DOM? Я не уверен, почему readAsBinarySring здесь медленный, поскольку использование .slice в большом двоичном объекте должно читать только ту часть, которую вы хотите, однако то, что вы описываете, указывает на то, что действительно он ждет всего файла.   -  person Benjamin Gruenbaum    schedule 17.02.2021
comment
@BenjaminGruenbaum, чтение файла с использованием потоков Response и DOM работает, но, к сожалению, не улучшает производительность чтения для больших файлов.   -  person kacase    schedule 17.02.2021
comment
@BenjaminGruenbaum Я добавил к вопросу реализацию DOM Stream.   -  person kacase    schedule 17.02.2021
comment
Невозможно воспроизвести здесь на macOS с SSD-накопителем. Не могли бы вы показать, что именно вы измеряете и как? Где хранятся ваши файлы? Что происходит, когда вы используете данные из памяти (new Blob([await file.arrayBuffer()]))? Браузеры должны делать снимок файла при первом доступе, но я думаю, что обычно для этого используется только поле lastModified, хотя вашей ОС также может потребоваться больше времени для доступа к метаданным файла для больших файлов.   -  person Kaiido    schedule 23.02.2021
comment
Привет, @Kaiido, мы измерили его, используя вкладку производительности в Chrome и анализируя снимок. Нам удалось воспроизвести ту же проблему в вашем stackblitz. Однако это не повлияет на установленный вами таймер. Похоже, что событие onchange вызывается только после того, как произошла некоторая файловая операция, и эта файловая операция увеличивается с размером файла. Время между добавлением файла и запуском события onchange зависит от размера файла.   -  person kacase    schedule 24.02.2021
comment
Значит FileReader тут ни при чем? Почему бы не прояснить это в вопросе? Для меня это действительно звучит так, будто вашей ОС требуется все это время, чтобы прикоснуться к файлу и произвести метаданные. Боюсь, что slice () ничего не может изменить. Что касается того, почему ваша ОС требует времени относительно размера файла, я понятия не имею. Возможно, стоит протестировать в других средах, с другим жестким диском, другой файловой системой и т. Д.   -  person Kaiido    schedule 24.02.2021
comment
@Kaiido, видимо, да. Я обновлю Вопрос. Похоже, это проблема с input типа File. Я проведу дополнительное тестирование и обновлю его соответственно.   -  person kacase    schedule 24.02.2021
comment
Я думаю, что время в основном тратится перед шагом «читать». Вы можете подумать о том, чтобы сосредоточиться на процессе получения файлов.   -  person 小聪聪到此一游    schedule 26.02.2021
comment
И чтение начала файла во время загрузки файла, а не после.   -  person 小聪聪到此一游    schedule 26.02.2021
comment
На какой платформе вы столкнулись с этой проблемой и с каким типом файлов?   -  person Dan Macák    schedule 27.02.2021
comment
Похоже, у нас будет запрос на изменение, исходящий из этого вопроса (просто наблюдая, как это происходит, я мог воспроизвести и не мог найти способ обойти это)   -  person Bob    schedule 01.03.2021
comment
Может быть полезно; Я определенно кое-что узнал здесь: stackoverflow.com/questions/14438187/ Я так понимаю, вы это видели?   -  person Todd    schedule 02.03.2021
comment
Итак, ваша основная проблема заключается в том, что для обработки файла требуется больше времени, прежде чем будет выполнен следующий код FileReader. Однако ради знаний, если вам нужно обработать большой объем данных или дорогостоящие операции, вам следует рассмотреть возможность использования веб-воркера (html5rocks.com/en/tutorials/file/filesystem-sync)   -  person Pierre Burton    schedule 02.03.2021
comment
Я предлагаю вам сделать это большими партиями по 1024b в цикле for от 1 до 10, я думаю, что это может изменить производительность. конечно, вы должны изменить начальную и конечную позиции в методе среза для каждой итерации.   -  person Itay wazana    schedule 02.03.2021