Como exportar informações da matriz JavaScript para csv (no lado do cliente)?

Eu sei que há muitas questões dessa natureza, mas eu preciso fazer isso usando JavaScript. Eu estou usando o Dojo 1.8 e tenho todas as informações de atributo na matriz, que se parece com isso:

 [["name1", "city_name1", ...]["name2", "city_name2", ...]] 

Alguma ideia de como posso exportar isso para CSV no lado do cliente?

Você pode fazer isso em JavaScript nativo. Você terá que analisar seus dados no formato CSV correto dessa forma (supondo que você esteja usando uma matriz de matrizes para seus dados, conforme descrito na pergunta):

 const rows = [["name1", "city1", "some other info"], ["name2", "city2", "more info"]]; let csvContent = "data:text/csv;charset=utf-8,"; rows.forEach(function(rowArray){ let row = rowArray.join(","); csvContent += row + "\r\n"; }); 

Então você pode usar as funções window.open e encodeURI do JavaScript para baixar o arquivo CSV da seguinte forma:

 var encodedUri = encodeURI(csvContent); window.open(encodedUri); 

Editar:

Se você quiser dar ao seu arquivo um nome específico, terá que fazer as coisas de forma um pouco diferente, já que isso não tem suporte para acessar um URI de dados usando o método window.open . Para conseguir isso, você pode criar um nó DOM oculto e definir seu atributo de download seguinte forma:

 var encodedUri = encodeURI(csvContent); var link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", "my_data.csv"); link.innerHTML= "Click Here to download"; document.body.appendChild(link); // Required for FF link.click(); // This will download the data file named "my_data.csv". 

Com base nas respostas acima, criei esta function que testei no IE 11, no Chrome 36 e no Firefox 29

 function exportToCsv(filename, rows) { var processRow = function (row) { var finalVal = ''; for (var j = 0; j < row.length; j++) { var innerValue = row[j] === null ? '' : row[j].toString(); if (row[j] instanceof Date) { innerValue = row[j].toLocaleString(); }; var result = innerValue.replace(/"/g, '""'); if (result.search(/("|,|\n)/g) >= 0) result = '"' + result + '"'; if (j > 0) finalVal += ','; finalVal += result; } return finalVal + '\n'; }; var csvFile = ''; for (var i = 0; i < rows.length; i++) { csvFile += processRow(rows[i]); } var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' }); if (navigator.msSaveBlob) { // IE 10+ navigator.msSaveBlob(blob, filename); } else { var link = document.createElement("a"); if (link.download !== undefined) { // feature detection // Browsers that support HTML5 download attribute var url = URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", filename); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } } 

Por exemplo: https://jsfiddle.net/jossef/m3rrLzk0/

Esta solução deve funcionar com o Internet Explorer 10+, Edge, versões antigas e novas do Chrome, FireFox, Safari, ++

A resposta aceita não funcionará com o IE e o Safari.

 // Example data given in question text var data = [ ['name1', 'city1', 'some other info'], ['name2', 'city2', 'more info'] ]; // Building the CSV from the Data two-dimensional array // Each column is separated by ";" and new line "\n" for next row var csvContent = ''; data.forEach(function(infoArray, index) { dataString = infoArray.join(';'); csvContent += index < data.length ? dataString + '\n' : dataString; }); // The download function takes a CSV string, the filename and mimeType as parameters // Scroll/look down at the bottom of this snippet to see how download is called var download = function(content, fileName, mimeType) { var a = document.createElement('a'); mimeType = mimeType || 'application/octet-stream'; if (navigator.msSaveBlob) { // IE10 navigator.msSaveBlob(new Blob([content], { type: mimeType }), fileName); } else if (URL && 'download' in a) { //html5 A[download] a.href = URL.createObjectURL(new Blob([content], { type: mimeType })); a.setAttribute('download', fileName); document.body.appendChild(a); a.click(); document.body.removeChild(a); } else { location.href = 'data:application/octet-stream,' + encodeURIComponent(content); // only this mime type is supported } } download(csvContent, 'dowload.csv', 'text/csv;encoding:utf-8'); 

Eu vim aqui procurando um pouco mais de conformidade com a RFC 4180 e não consegui encontrar uma implementação, então fiz uma (possivelmente ineficiente) para minhas próprias necessidades. Eu pensei em compartilhar com todos.

 var content = [['1st title', '2nd title', '3rd title', 'another title'], ['aa a', 'bb\nb', 'cc,c', 'dd"d'], ['www', 'xxx', 'yyy', 'zzz']]; var finalVal = ''; for (var i = 0; i < content.length; i++) { var value = content[i]; for (var j = 0; j < value.length; j++) { var innerValue = value[j]===null?'':value[j].toString(); var result = innerValue.replace(/"/g, '""'); if (result.search(/("|,|\n)/g) >= 0) result = '"' + result + '"'; if (j > 0) finalVal += ','; finalVal += result; } finalVal += '\n'; } console.log(finalVal); var download = document.getElementById('download'); download.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(finalVal)); download.setAttribute('download', 'test.csv'); 

Espero que isso ajude alguém no futuro. Isso combina a codificação do CSV junto com a capacidade de baixar o arquivo. No meu exemplo no jsfiddle . Você pode baixar o arquivo (assumindo o navegador HTML 5) ou visualizar a saída no console.

ATUALIZAR:

O Chrome agora parece ter perdido a capacidade de nomear o arquivo. Não tenho certeza do que aconteceu ou como corrigi-lo, mas sempre que eu uso esse código (incluindo o jsfiddle), o arquivo baixado agora é chamado de download.csv .

A solução do @Default funciona perfeitamente no Chrome (muito obrigado por isso!), Mas eu tive um problema com o IE.

Aqui está uma solução (funciona no IE10):

 var csvContent=data; //here we load our csv data var blob = new Blob([csvContent],{ type: "text/csv;charset=utf-8;" }); navigator.msSaveBlob(blob, "filename.csv") 

Na atualização do Chrome 35, o comportamento do atributo de download foi alterado.

https://code.google.com/p/chromium/issues/detail?id=373182

para trabalhar isso no chrome, use isso

 var pom = document.createElement('a'); var csvContent=csv; //here we load our csv data var blob = new Blob([csvContent],{type: 'text/csv;charset=utf-8;'}); var url = URL.createObjectURL(blob); pom.href = url; pom.setAttribute('download', 'foo.csv'); pom.click(); 

Ai está :

     Download CSV    
 //It work in Chrome and IE ... I reviewed and readed a lot of answer. then i used it and tested in both ... var link = document.createElement("a"); if (link.download !== undefined) { // feature detection // Browsers that support HTML5 download attribute var blob = new Blob([CSV], { type: 'text/csv;charset=utf-8;' }); var url = URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", fileName); link.style = "visibility:hidden"; } if (navigator.msSaveBlob) { // IE 10+ link.addEventListener("click", function (event) { var blob = new Blob([CSV], { "type": "text/csv;charset=utf-8;" }); navigator.msSaveBlob(blob, fileName); }, false); } document.body.appendChild(link); link.click(); document.body.removeChild(link); //Regards 

Trabalhando para todos os idiomas

  function convertToCsv(fName, rows) { var csv = ''; for (var i = 0; i < rows.length; i++) { var row = rows[i]; for (var j = 0; j < row.length; j++) { var val = row[j] === null ? '' : row[j].toString(); val = val.replace(/\t/gi, " "); if (j > 0) csv += '\t'; csv += val; } csv += '\n'; } // for UTF-16 var cCode, bArr = []; bArr.push(255, 254); for (var i = 0; i < csv.length; ++i) { cCode = csv.charCodeAt(i); bArr.push(cCode & 0xff); bArr.push(cCode / 256 >>> 0); } var blob = new Blob([new Uint8Array(bArr)], { type: 'text/csv;charset=UTF-16LE;' }); if (navigator.msSaveBlob) { navigator.msSaveBlob(blob, fName); } else { var link = document.createElement("a"); if (link.download !== undefined) { var url = window.URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", fName); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); } } } convertToCsv('download.csv', [ ['Order', 'Language'], ['1', 'English'], ['2', 'Español'], ['3', 'Français'], ['4', 'Português'], ['5', 'čeština'], ['6', 'Slovenščina'], ['7', 'Tiếng Việt'], ['8', 'Türkçe'], ['9', 'Norsk bokmål'], ['10', 'Ελληνικά'], ['11', 'беларускі'], ['12', 'русский'], ['13', 'Українська'], ['14', 'հայերեն'], ['15', 'עִברִית'], ['16', 'اردو'], ['17', 'नेपाली'], ['18', 'हिंदी'], ['19', 'ไทย'], ['20', 'ქართული'], ['21', '中国'], ['22', '한국어'], ['23', '日本語'], ]) 

Crie um blob com os dados csv .ie var blob = new Blob([data], type:"text/csv");

Se o navegador suportar o salvamento de blobs, ou seja, if window.navigator.mSaveOrOpenBlob)===true , salve os dados csv usando: window.navigator.msSaveBlob(blob, 'filename.csv')

Se o navegador não suportar salvar e abrir blobs, salve os dados csv como:

 var downloadLink = document.createElement(''); downloadLink.attr('href', window.URL.createObjectURL(blob)); downloadLink.attr('download', filename); downloadLink.attr('target', '_blank'); document.body.append(downloadLink); 

Snippet de código completo:

 var filename = 'data_'+(new Date()).getTime()+'.csv'; var charset = "utf-8"; var blob = new Blob([data], { type: "text/csv;charset="+ charset + ";" }); if (window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveBlob(blob, filename); } else { var downloadLink = document.element(''); downloadLink.attr('href', window.URL.createObjectURL(blob)); downloadLink.attr('download', filename); downloadLink.attr('target', '_blank'); document.body.append(downloadLink); downloadLink[0].click(); } 

Há duas perguntas aqui:

  1. Como converter um array para string csv
  2. Como salvar essa string em um arquivo

Todas as respostas para a primeira pergunta (exceto a da Milimetric) aqui parecem um exagero. E o da Milimetric não cobre os requisitos altrativos, como cercar strings com aspas ou converter arrays de objects.

Aqui estão minhas opiniões sobre isso:

Para um simples csv, um mapa () e um join () são suficientes:

  var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]]; var csv = test_array.map(function(d){ return d.join(); }).join('\n'); /* Results in name1,2,3 name2,4,5 name3,6,7 name4,8,9 name5,10,11 

Esse método também permite que você especifique o separador de coluna diferente de uma vírgula na união interna. por exemplo, uma guia: d.join('\t')

Por outro lado, se você quiser fazê-lo corretamente e colocar strings entre aspas “”, então você pode usar alguma mágica JSON:

 var csv = test_array.map(function(d){ return JSON.stringify(d); }) .join('\n') .replace(/(^\[)|(\]$)/mg, ''); // remove opening [ and closing ] // brackets from each line /* would produce "name1",2,3 "name2",4,5 "name3",6,7 "name4",8,9 "name5",10,11 

se você tiver uma matriz de objects como:

 var data = [ {"title": "Book title 1", "author": "Name1 Surname1"}, {"title": "Book title 2", "author": "Name2 Surname2"}, {"title": "Book title 3", "author": "Name3 Surname3"}, {"title": "Book title 4", "author": "Name4 Surname4"} ]; // use var csv = data.map(function(d){ return JSON.stringify(Object.values(d)); }) .join('\n') .replace(/(^\[)|(\]$)/mg, ''); 

Uma function de seta com o ES6:

 const dataToCsvURI = (data) => encodeURI( `data:text/csv;charset=utf-8,${data.map((row, index) => row.join(',')).join(`\n`)}` ); 

Então :

 window.open( dataToCsvURI( [["name1", "city_name1"/*, ...*/], ["name2", "city_name2"/*, ...*/]] ) ); 

Caso alguém precise disso para reactjs , o react react-csv está lá para isso

Aqui está como eu faço o download de arquivos CSV no lado do cliente no meu aplicativo Java GWT. Um agradecimento especial a Xavier John pela sua solução. Foi verificado que funciona em FF 24.6.0, IE 11.0.20 e Chrome 45.0.2454.99 (64 bits). Espero que isso poupe um pouco de tempo:

 public class ExportFile { private static final String CRLF = "\r\n"; public static void exportAsCsv(String filename, List> data) { StringBuilder sb = new StringBuilder(); for(List row : data) { for(int i=0; i0) sb.append(","); sb.append(row.get(i)); } sb.append(CRLF); } generateCsv(filename, sb.toString()); } private static native void generateCsv(String filename, String text) /*-{ var blob = new Blob([text], { type: 'text/csv;charset=utf-8;' }); if (navigator.msSaveBlob) // IE 10+ { navigator.msSaveBlob(blob, filename); } else { var link = document.createElement("a"); if (link.download !== undefined) // feature detection { // Browsers that support HTML5 download attribute var url = URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", filename); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } }-*/; } 

Aqui está uma versão amigável angular:

  constructor(private location: Location, private renderer: Renderer2) {} download(content, fileName, mimeType) { const a = this.renderer.createElement('a'); mimeType = mimeType || 'application/octet-stream'; if (navigator.msSaveBlob) { navigator.msSaveBlob(new Blob([content], { type: mimeType }), fileName); } else if (URL && 'download' in a) { const id = GetUniqueID(); this.renderer.setAttribute(a, 'id', id); this.renderer.setAttribute(a, 'href', URL.createObjectURL(new Blob([content], { type: mimeType }))); this.renderer.setAttribute(a, 'download', fileName); this.renderer.appendChild(document.body, a); const anchor = this.renderer.selectRootElement(`#${id}`); anchor.click(); this.renderer.removeChild(document.body, a); } else { this.location.go(`data:application/octet-stream,${encodeURIComponent(content)}`); } }; 

As respostas acima funcionam, mas tenha em mente que se você está abrindo no formato .xls, as colunas ~ ~ podem ~ ~ ser separadas por '\t' vez de ',' , a resposta https://stackoverflow.com/ a / 14966131/6169225 funcionou bem para mim, desde que eu usei .join('\t') nos arrays em vez de .join(',') .

Caso alguém precise disso para knockout js, funciona basicamente com a solução proposta:

html:

 Download 

modelo de visualização:

 // for the download link this.filename = ko.computed(function () { return ko.unwrap(this.id) + '.csv'; }, this); this.csvContent = ko.computed(function () { if (!this.csvLink) { var data = ko.unwrap(this.data), ret = 'data:text/csv;charset=utf-8,'; ret += data.map(function (row) { return row.join(','); }).join('\n'); return encodeURI(ret); } }, this); 

Eu adicionei a function de Xavier Johns para include também os headers de campo, se necessário, embora use jQuery. O bit $ .each precisará ser alterado para um loop nativo de javascript

 function exportToCsv(filename, rows, headers = false) { var processRow = function (row) { row = $.map(row, function(value, index) { return [value]; }); var finalVal = ''; for (var j = 0; j < row.length; j++) { if(i == 0 && j == 0 && headers == true){ var ii = 0; $.each(rows[i], function( index, value ) { //console.log(index); var fieldName = index === null ? '' : index.toString(); //console.log(fieldName); var fieldResult = fieldName.replace(/"/g, '""'); //console.log(fieldResult); if (fieldResult.search(/("|,|\n)/g) >= 0){ fieldResult = '"' + fieldResult + '"'; } //console.log(fieldResult); if (ii > 0){ finalVal += ','; finalVal += fieldResult; }else{ finalVal += fieldResult; } ii++; //console.log(finalVal); }); finalVal += '\n'; //console.log('end: '+finalVal); } var innerValue = row[j] === null ? '' : row[j].toString(); if (row[j] instanceof Date) { innerValue = row[j].toLocaleString(); }; var result = innerValue.replace(/"/g, '""'); if (result.search(/("|,|\n)/g) >= 0){ result = '"' + result + '"'; } if (j > 0){ finalVal += ','; finalVal += result; }else{ finalVal += result; } } return finalVal + '\n'; }; var csvFile = ''; for (var i = 0; i < rows.length; i++) { csvFile += processRow(rows[i]); } var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' }); if (navigator.msSaveBlob) { // IE 10+ navigator.msSaveBlob(blob, filename); }else{ var link = document.createElement("a"); if (link.download !== undefined) { // feature detection // Browsers that support HTML5 download attribute var url = URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", filename); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } } 

Esta é uma resposta modificada com base na resposta aceita, em que os dados seriam provenientes de JSON.

  JSON Data Ouptut: 0 :{emails: "SAMPLE Co., peter@samplecompany.com"}, 1:{emails: "Another CO. , ronald@another.com"} JS: $.getJSON('yourlink_goes_here', { if_you_have_parameters}, function(data) { var csvContent = "data:text/csv;charset=utf-8,"; var dataString = ''; $.each(data, function(k, v) { dataString += v.emails + "\n"; }); csvContent += dataString; var encodedUri = encodeURI(csvContent); var link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", "your_filename.csv"); document.body.appendChild(link); // Required for FF link.click(); }); 

Um monte de soluções roll-your-own aqui para converter dados para CSV, mas apenas sobre todos eles terão várias ressalvas em termos do tipo de dados que irão formatar corretamente sem tropeçar no Excel ou os gostos.

Por que não usar algo comprovado: Papa Parse

 Papa.unparse(data[, config]) 

Então, basta combinar isso com uma das soluções de download local aqui, por exemplo. o de @ArneHB parece ser bom.

Eu uso essa function para converter uma string[][] em um arquivo csv. Ele cita uma célula, se ela contiver um " , um ou outro espaço em branco (exceto espaços em branco):

 /** * Takes an array of arrays and returns a `,` sparated csv file. * @param {string[][]} table * @returns {string} */ function toCSV(table) { return table .map(function(row) { return row .map(function(cell) { // We remove blanks and check if the column contains // other whitespace,`,` or `"`. // In that case, we need to quote the column. if (cell.replace(/ /g, '').match(/[\s,"]/)) { return '"' + cell.replace(/"/g, '""') + '"'; } return cell; }) .join(','); }) .join('\n'); // or '\r\n' for windows 

}

Nota : não funciona no Internet Explorer <11, a menos que o map seja polifiliado.

Nota : Se as células contiverem números, você poderá adicionar cell=''+cell before if (cell.replace... para converter números em strings.

Ou você pode escrever em uma linha usando o ES6:

 t.map(r=>r.map(c=>c.replace(/ /g, '').match(/[\s,"]/)?'"'+c.replace(/"/g,'""')+'"':c).join(',')).join('\n')