Вопрос Как победить javascript на download сформированного *.csv размером более 2-х мегабайт?

Статус
В этой теме нельзя размещать новые ответы.

pvvx

Активный участник сообщества
Как победить javascript на download сформированного *.csv размером более 2-х мегабайт?

Имеется:
Web-сервер на устройстве... Он отдает данные в Json с датчиков в виде 32 float значений в несколько ms.
Json опрашивается-принимается AJAX-ом и на HTML странице (загруженной с устройства, c его web) в работающем javascript отрисовываются графики... происходит накопление до 5000 пачек в виде 32 float + флаги...
На HTML описана кнопка сохранения данных в CSV формате и javascript примерно такого содержания:
JavaScript:
$("butSave").onclick =  function() {
    console.log('Dbase length: '+dbase.length);
    var data = 'data:text/csv;charset=windows-1251,'+UnicodeToWin1251(dev.cfg.txt.flags.join(';'))+';'+UnicodeToWin1251(dev.cfg.txt.params.join(';'))+ "\n";
    dbase.forEach(function(it, idx){data+=it.t.toISOString()+';'+it.tt+';'+it.mode+';'+UnicodeToWin1251(it.flg.join(';'))+';'+UnicodeToWin1251(it.f.join(';'))+'\n';});
    var link = document.createElement('a');
    link.setAttribute('href', data);
    link.setAttribute('download',"data.csv");
    console.log('CSVData length: '+data.length);
    link.click();
}
По мере накопления данных размер CSV для сохранения увеличивается...
При размере сформированных данных CSV менее 2-х мегабайт файл успешно сохраняетcя в Chrome (для Firefox пишут, что ограничение до 1 040 000 байт). Далее кнопка ‘butSave’ на форме ничего не делает :(
При 5000 пачек замеров console log пишет:
Dbase length: 5000
CSVData length: 3230703

и $("butSave").onclick = function() не сохраняет файл и вообще ничего делает, кроме печати отмеченного в console log :eek:
 

Алексей.

Active member
Шесть мегов хватит? Проверил на фф хроме ие11
Код:
<!doctype html>
<body onload="on_load();"></body>
<script type="text/javascript">
  
   function download(data, filename, type) {
       var file = new Blob([data], {type: type});
       if (window.navigator.msSaveOrOpenBlob) { // ie10+
           window.navigator.msSaveOrOpenBlob(file, filename);
       } else { // ff, chrome
           url = URL.createObjectURL(file);
           var a = document.createElement("a");
           a.href = url;
           a.download = filename;
           document.body.appendChild(a);
           a.click();
           setTimeout(function() {document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0);
       }
   }
  
   function on_load() {
       var data = '';
       while (data.length < 6000000) {
           data += '1.23;4.56;7.89;0;0;0;0;0;0;0;0;0;0;0;0\r\n';
       }
       download(data, 'test.csv', 'text/csv');
   }
</script>
 
  • Like
Реакции: pvvx

pvvx

Активный участник сообщества
Шесть мегов хватит? Проверил на фф хроме ие11
ie11 вообще требует другого обращения и на него не ставится, т.к. не популярен. На мобилках его нет.
И проблем. там в том, что заголовок и формат данных 'data:text/csv;charset=windows-1251,' идет в начале всей строки, а такой компонент ограничен где-то в нутрах эксплореров.
Нужен другой метод сохранения данных.
 

Алексей.

Active member
Перечитал ещё раз первый пост, про мобилки не ничего не заметил.
Проверял фф и хром на ПК с убунтой, ие11 на гостевом с виндовс8.
Доеду до дома, на андроиде проверю.
 

pvvx

Активный участник сообщества
Перечитал ещё раз первый пост, про мобилки не ничего не заметил.
Проверял фф и хром на ПК с убунтой, ие11 на гостевом с виндовс8.
Доеду до дома, на андроиде проверю.
var aBlob = new Blob( array, options ); где: array - массив Array из объектов ArrayBuffer, ArrayBufferView, Blob, DOMString, или смесь любых из подобных объектов, которая может быть размещена внутри Blob. DOMStrings представлены в кодировке UTF-8. А для Exel надо charset=windows-1251.
Где там перекодировку впихнуть? Иначе текст в файле выдает в %xx
 

Алексей.

Active member
Насколько я понял, csv текстовый файл, содержит значения накопленных данных, флоатов и флагов, я полагал что это цифры точки запятые и всякие true false.
У вас передается что то ещё локализованное?
 

pvvx

Активный участник сообщества
Насколько я понял, csv текстовый файл, содержит значения накопленных данных, флоатов и флагов, я полагал что это цифры точки запятые и всякие true false.
У вас передается что то ещё локализованное?
К примеру рус.Exel читает числа в формате с ',' , а не с '.'. Надо перекодировать точку в запятую у чисел.
Так-же Exel в csv жрет и такое:
JavaScript:
    var data = '';
    var i = 1;
    while (data.length < 6000000) {
        data += new Date().toISOString()+';"=ДАТАЗНАЧ(ПСТР(A'+i+';1;10))+ВРЕМЗНАЧ(ПСТР(A'+i+';12;8))";'+(((i&2)==0)?'Включено':'Выключено')+';1,23;4,56;7,89;0;0;0;0;0;0;0;0;0;0;0;0\n';
        i++;
    }
В итоге, в Exel, получится преобразованное время в его формат во втором столбце. Ну и т.д. :)
Хотя вопрос с размером data при раскидывании на теги решился, но локализация всегда нужна...
 

Алексей.

Active member
На андроеде, фф версия 66.0 и хром версия 73.0 сохраняют 6 мегов не локализованного csv и этот csv открываются wps офисом почему то.
Попробую добавить кириллицу.
 

pvvx

Активный участник сообщества
Да, ещё - обычно в csv в первой строке заголовки и их надо как-то 'кириллизовать' или "китайнизировать' :)
Мы же локально сохраняем файл csv, а не в глобалку...
 

pvvx

Активный участник сообщества
Нашел вариант:
JavaScript:
    var str = data.toString('windows-1251', 0, data.length)
    download(str, 'test.csv', 'text/csv;charset=windows-1251');
Ну и далее уже по подобию...
 

Алексей.

Active member
var aBlob = new Blob( array, options ); где: array - массив Array из объектов ArrayBuffer, ArrayBufferView, Blob, DOMString, или смесь любых из подобных объектов, которая может быть размещена внутри Blob. DOMStrings представлены в кодировке UTF-8. А для Exel надо charset=windows-1251.
А если не utf-8, а windows-1251, то что должно происходить?
Добавил перекодировку, вроде в таблице не напутал.
Типа сохраняется в вин-1251 и открывается либреофисом и wps офисом.
HTML:
<!doctype html>
<html lang="ru">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body onload="on_load();"></body>
<script type="text/javascript">

   function download(data, filename, type) {
       var uint8 = new Uint8Array(data.length);
       for(var i = 0; i < data.length; i++) {
           x = data.charCodeAt(i);
           if (x >= 1040 && x <= 1103) { // А..Яа..я
               x -= 848;
           } else if (x == 1025) {   // Ё
               x = 168;
           } else if (x == 1105) {   // ё
               x = 184;
           }
           uint8[i] = x;
       }
       var file = new Blob([uint8], {type: type});
       if (window.navigator.msSaveOrOpenBlob) { // ie10+
           window.navigator.msSaveOrOpenBlob(file, filename);
       } else { // ff, chrome
           var url = URL.createObjectURL(file);
           var a = document.createElement("a");
           a.href = url;
           a.download = filename;
           document.body.appendChild(a);
           a.click();
           setTimeout(function() {document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0);
       }
   }

   function on_load() {
       var data = '';
       for (var i = 1; data.length < 6000000; i++) {
           data += 'Строка ' + i + ';1,23;4,56;7,89;0;0;0;0;0;0;0;0;0;0;0;0' + '\r\n';
       }
       download(data, 'test.csv', 'text/csv');
   }

</script>
</html>
 

pvvx

Активный участник сообщества
А если не utf-8, а windows-1251, то что должно происходить?
Exel жрет utf-8. Для этого надо прописать в начало csv файла 3 байта: 0xef,0xbb,0xbf. Тогда перекодировать ничего не требуется. Но сделать это не удалось. Не знаю как в javascript вставить спец символы в string.
Такие варианты не пройдут - у нас система другая... :)
 

fps

Member
Вообще, в JS вот так очень не рекомендуется (медленно и память жрет), особенно при большой длине:
JavaScript:
 var data = '';
    var i = 1;
    while (data.length < 600000) {
        data += new Date().toString()+'\n';
        i++;
    }
Лучше push в массив и в конце join его в строку. Типа такого:
JavaScript:
 var data = [];
    while (data.length < 60000) {
        data.push(new Date().toString());
    }
data=data.join('\n')
 

Алексей.

Active member
Exel жрет utf-8. Для этого надо прописать в начало csv файла 3 байта: 0xef,0xbb,0xbf. Тогда перекодировать ничего не требуется. Но сделать это не удалось. Не знаю как в javascript вставить спец символы в string.
Такие варианты не пройдут - у нас система другая... :)
Да зачем же всё в стринг засовывать, ничего полезного из этого не получается.
Именно по этому, я и преобразую коды символов, представленных как интеджер, и сохраняю в типизированный массив беззнаковых 8-ми битных интеджеров - Uint8Array, от него же и блоб строю.
Фактически данные в блоб-е произвольные, текст, изображения, архив и т.п.
Сейчас сохраняю в вин-1251, при открытии файла, либреофис предлагает выбрать кодировку для файла. На смартфоне, wps офис открывает сразу, про кодировку не спрашивая.
Мой пример у вас не заработал?
П.С.
На excel пока денег жалко.
 

pvvx

Активный участник сообщества
Сейчас сохраняю в вин-1251, при открытии файла, либреофис предлагает выбрать кодировку для файла. На смартфоне, wps офис открывает сразу, про кодировку не спрашивая.
Подумав, поразмыслив, и по вашему первому вопросу - если можно ничего не перекодировать, то и незачем это делать. Если жрут utf-8 все, включая разные программы что нашел, то так и выходит проще.
Мой пример у вас не заработал?
Да. Спасибо. Я всё учитываю и накапливаю...
На excel пока денег жалко.
Он у меня, как и win официальная, оплаченная. Как в конторе иначе, если и на домашнем компе работаю?
 

pvvx

Активный участник сообщества
Вообще, в JS вот так очень не рекомендуется (медленно и память жрет), особенно при большой длине:
...
Лучше push в массив и в конце join его в строку. Типа такого:
Памяти не жалко и производительности так-же. Приложение, в котором участвует данная система рассчитано на единичные сохранения в случае обнаружения каких-либо глюков в системе и для передачи специалистам. А графическая информация (графики) и прочее для диспетчера или другого пользователя отображается и обрабатывается другой частью (тоже на javascript) совместно web-серваком и виртуальным устройством встроенным в систему на Linux...
Это как дамп при сбое...
 

pvvx

Активный участник сообщества
Концепция вышла такая: на пользователе запускается типа драйвер на javascript. Он обеспечивает вязь с сервером и разгребает полученные данные и описания к ним по сложным шаблонам. Графики так-же запрашивают у него данные для построения... Сам HTML при этом пишет кто угодно, вплоть до нанятого дизайнера. Но надо обеспечить минимальную функциональность - в данном случае кнопку сохранения данных в csv для сложных случаев поведения самого контролируемого объекта. И тут чем инфы больше, тем лучше. От этого csv и выходит мегабайтный...
 

pvvx

Активный участник сообщества
(Поведение виртуального устройства и что ему отдавать в Json или в XLS и типа описывается особым скриптом. Как принимать данные от источников и их обрабатывать - аналогично. Расчет всего на то, что можно описать практически любое устройство с накоплением данных.)
 

pvvx

Активный участник сообщества
И т.к. контролируемые устройства не строго одинаковые, а отличаются, то битики превращаются в названия и они на русском языке. А это уже стринг. В таком виде и может выходить csv. Ну типа "включено/выключено" "Старт/Стоп/Ожидает" и т.д. , а не "1"/"0" в которых потом никто не разберется, т.к. данных с устройств поступает много и это не Arduino - на каждый бит или значение должны быть: оценка качества сигнала, вкл.откл. обработка и т.д. Как на атомной станции :).
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху Снизу