• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Вопрос Как победить 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

Active 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 - на каждый бит или значение должны быть: оценка качества сигнала, вкл.откл. обработка и т.д. Как на атомной станции :).
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху Снизу