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

513

Sei que há muitas perguntas dessa natureza, mas preciso fazer isso usando JavaScript. Estou usando Dojo 1.8e tenho todas as informações de atributo na matriz, que se parece com isso:

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

Alguma idéia de como eu posso exportar isso para CSVo lado do cliente?

Sam007
fonte

Respostas:

837

Você pode fazer isso em JavaScript nativo. Você precisará analisar seus dados no formato CSV correto da seguinte maneira (supondo que você esteja usando uma matriz de matrizes para os 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";
});

ou a maneira mais curta (usando as funções das setas ):

const rows = [
    ["name1", "city1", "some other info"],
    ["name2", "city2", "more info"]
];

let csvContent = "data:text/csv;charset=utf-8," 
    + rows.map(e => e.join(",")).join("\n");

Depois, você pode usar JavaScript window.opene encodeURIfunções para baixar o arquivo CSV da seguinte maneira:

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

Editar:

Se você quiser atribuir um nome específico ao arquivo, faça as coisas de maneira um pouco diferente, pois não há suporte para acessar um URI de dados usando o window.openmétodo Para conseguir isso, você pode criar um <a>nó DOM oculto e definir seu downloadatributo da seguinte maneira:

var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "my_data.csv");
document.body.appendChild(link); // Required for FF

link.click(); // This will download the data file named "my_data.csv".
Padrão
fonte
4
Pelo que sei, não há uma maneira de fazer isso usando window.open. No entanto, você pode criar um link oculto que tenha um downloadatributo definido para o nome do arquivo desejado. Em seguida, "clicar" neste link fará o download do arquivo com o nome que você deseja, acrescentarei à minha resposta.
Padrão
14
Eu tive que adicionar document.body.appendChild(link);para obter suporte completo no FF.
Hardbyte 25/02
9
Esta resposta está errada: falhará no caso data = [["Hello, world"]]. Isso produzirá duas colunas quando deve gerar uma.
Aredridel 22/07/2015
18
Isso funciona bem para aproximadamente ~ 7000 linhas. Mas começa a dar esse erro: NETWORK_INVALID_REQUEST . Há mais alguém enfrentando esse problema também? Existe algum limite superior de dados na encodeURIComponent()função ou algo assim? Estou usando o Chrome como navegador.
Abhidemon
13
@ Abhidemon A resposta é que você tem que usar um tipo de blob para algo tão grande que funcione bem, por exemplo: blob = new Blob ([csvContent], {type: "text / csv"}); href = window.URL.createObjectURL (blob); Mais detalhes: stackoverflow.com/a/19328891/1854079
mdubez
257

Com base nas respostas acima, criei esta função que testei no IE 11, Chrome 36 e 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/

Xavier John
fonte
6
Poderia recorrer a window.openum elsede link.download !== undefined.
MrYellow
2
Este é um bom pedaço de código. Alguma chance de você estar disposto a licenciar isso com algo mais liberal do que o padrão SO do CC-BY-SA? Por exemplo, CC0, MIT, BSD, Apache, X11. . . meta.stackexchange.com/questions/12527/…
joseph_morris
1
Eu tenho usado esse método para implementar a exportação do Excel em alguns aplicativos da web. Mas o Chrome 43+ agora mudou os atributos do DOM para a cadeia de protótipos. Uma exceção é lançada em link.style.visibility='hidden'. B / c o atributo DOM é somente leitura. Mais detalhes podem ser encontrados em updates.html5rocks.com/2015/04/… na seção "A gravação em propriedades somente leitura no modo estrito gera um erro"
Blaise
1
Esta resposta é a melhor até agora. Inclui casos com caracteres especiais e parênteses.
Vladimir Kostov
2
Usei a seção de download desta resposta e funcionou bem no Chrome, obrigado!
Liran H
77

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');

A execução do snippet de código fará o download dos dados simulados como csv

Créditos para dandavis https://stackoverflow.com/a/16377813/1350598

Arne H. Bitubekk
fonte
1
(No mínimo, o código HTML5) funciona sem o setTimeout.
precisa saber é o seguinte
@StubbornShowaGuy arrefecer então eu vou remover o setTimeout do código de exemplo :)
Arne H. Bitubekk
Funciona no mais recente Chrome, IE e Firefox. Obrigado!
walla
A única solução verdadeiramente para vários navegadores aqui. Observe que funciona no Safari 10.10 e no Safari móvel. No entanto, a iframesecção pode ser substituído por apenas location.href = ...
Dan
2
NOTA: Há um erro de digitação na função, na verdade é URL.createObjectURL(termina com URLnão Url).
21717 Nathan Hinchey
35

Vim para cá procurando um pouco mais de conformidade com a RFC 4180 e não consegui encontrar uma implementação, por isso 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'], ['a a 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 e a capacidade de baixar o arquivo. No meu exemplo no jsfiddle . Você pode fazer o download do arquivo (assumindo o navegador HTML 5) ou visualizar a saída no console.

ATUALIZAR:

Agora, o Chrome parece ter perdido a capacidade de nomear o arquivo. Não sei ao certo o que aconteceu ou como corrigi-lo, mas sempre que uso esse código (incluindo o jsfiddle), o arquivo baixado agora é nomeado download.csv.

Uxonith
fonte
Boa captura Chris, eu não testá-lo com dados numéricos :)
Uxonith
Não sei se a última verificação nula é necessariamente um comportamento esperado. Nulo é muito diferente de uma sequência vazia. Se alguém implementasse isso, eu recomendaria um valor nulo personalizado (por exemplo: '[[NULL]]' '). Uma exceção para indefinido também pode ser desejada, mas eu recomendaria não substituir null por uma string vazia.
Uxonith
Eu testei e descobri que você está correto. Isso parece funcionar no Chrome e no Opera. O Safari apenas abre uma página com o conteúdo. Internet Explorer ... bem, é o IE. Para minha situação, vou gerar meu servidor CSV e servi-lo dessa maneira, infelizmente.
Uxonith
33

A solução do @Default funciona perfeitamente no Chrome (muito obrigado por isso!), Mas 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")
Dzarek
fonte
23

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 este

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();
Monu
fonte
1
Você também pode verificar este: github.com/mholt/PapaParse/issues/175#issuecomment-201308792
Gabriel
Esta é a resposta correta no momento, não a marcada como aceita!
meow
17

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', '日本語'],
    ])
Serdar Didan
fonte
Impressionante! (+1). Bem-vindo ao StackOverflow, amigo!
precisa saber é o seguinte
você pode me ajudar a entender o que é esse bloco de código UTF-16 e para que é usado aqui?
Mar1009 23/11/19
Oi Mar1009. Isso é necessário para alguns idiomas. Por exemplo, o alfabeto cirílico.
Serdar Didan 28/11/19
13

Ai está :

<!doctype html>  
<html>  
<head></head>  
<body>
<a href='#' onclick='downloadCSV({ filename: "stock-data.csv" });'>Download CSV</a>

<script type="text/javascript">  
    var stockData = [
        {
            Symbol: "AAPL",
            Company: "Apple Inc.",
            Price: "132.54"
        },
        {
            Symbol: "INTC",
            Company: "Intel Corporation",
            Price: "33.45"
        },
        {
            Symbol: "GOOG",
            Company: "Google Inc",
            Price: "554.52"
        },
    ];

    function convertArrayOfObjectsToCSV(args) {
        var result, ctr, keys, columnDelimiter, lineDelimiter, data;

        data = args.data || null;
        if (data == null || !data.length) {
            return null;
        }

        columnDelimiter = args.columnDelimiter || ',';
        lineDelimiter = args.lineDelimiter || '\n';

        keys = Object.keys(data[0]);

        result = '';
        result += keys.join(columnDelimiter);
        result += lineDelimiter;

        data.forEach(function(item) {
            ctr = 0;
            keys.forEach(function(key) {
                if (ctr > 0) result += columnDelimiter;

                result += item[key];
                ctr++;
            });
            result += lineDelimiter;
        });

        return result;
    }

    window.downloadCSV = function(args) {
        var data, filename, link;

        var csv = convertArrayOfObjectsToCSV({
            data: stockData
        });
        if (csv == null) return;

        filename = args.filename || 'export.csv';

        if (!csv.match(/^data:text\/csv/i)) {
            csv = 'data:text/csv;charset=utf-8,' + csv;
        }
        data = encodeURI(csv);

        link = document.createElement('a');
        link.setAttribute('href', data);
        link.setAttribute('download', filename);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
       }
</script>  
</body>  
</html>  
Madhulika Mukherjee
fonte
1
Resposta incrível. Estou votando mais uma vez, pois a resposta aceita, por algum motivo, coloca tudo em uma única coluna. Isso divide tudo em colunas separadas e o suporte ao formato de dados JSON é incrivelmente útil.
Hoser
Isso funciona quando o link é adicionado pela primeira vez ao corpo do documento e, em seguida, o clique é chamado. E então é removido do dom.
Jay Dubal
1
Boa resposta, a única desvantagem é que ele não funciona corretamente quando os dados têm um delimitador de coluna "," ou seja, Endereço: '10 Faixa de loop infinito, sala 56 ', observe a vírgula após a faixa. Eu sugiro que você use PapaParse ligação para converter os dados em CSV, em seguida, usar o método acima downloadCSV para o download do arquivo real
phil
Isso funciona perfeito para mim. Só tenho um problema, tenho alguns números na matriz como '000002342', mas quando exportados para csv, os zeros à esquerda são removidos. Existe alguma maneira de evitar isso?
Aakarsh Dhawan 28/10/19
13

O pessoal está tentando criar sua própria string csv, que falha em casos extremos, por exemplo, caracteres especiais e outros, certamente esse é um problema resolvido, certo?

papaparse - use para codificação JSON para CSV. Papa.unparse().

import Papa from "papaparse";

const downloadCSV = (args) => {  

  let filename = args.filename || 'export.csv';
  let columns = args.columns || null;

  let csv = Papa.unparse({ data: args.data, fields: columns})
  if (csv == null) return;

  var blob = new Blob([csv]);
  if (window.navigator.msSaveOrOpenBlob)  // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
      window.navigator.msSaveBlob(blob, args.filename);
  else
  {
      var a = window.document.createElement("a");
      a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
      a.download = filename;
      document.body.appendChild(a);
      a.click();  // IE: "Access is denied"; see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
      document.body.removeChild(a);
  }

}

Exemplo de uso

downloadCSV({ 
  filename: 'filename.csv',
  data: [{'a': '1', 'b': 2'}],
  columns: ['a','b']
});

https://github.com/mholt/PapaParse/issues/175 - Veja este comentário para obter uma discussão sobre o suporte ao navegador.

Glen Thompson
fonte
10

Você pode usar o trecho de código abaixo para exportar a matriz para o arquivo CSV usando Javascript.

Também lida com parte de caracteres especiais

var arrayContent = [["Séjour 1, é,í,ú,ü,ű"],["Séjour 2, é,í,ú,ü,ű"]];
var csvContent = arrayContent.join("\n");
var link = window.document.createElement("a");
link.setAttribute("href", "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURI(csvContent));
link.setAttribute("download", "upload_data.csv");
link.click(); 

Aqui está o link para trabalhar com o jsfiddle

Vignesh Subramanian
fonte
1
Melhor resposta para caracteres especiais
Alejandro
# (hashtag) não funciona!
Nakres 3/03
7
//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
Mauri
fonte
6

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('<a></a>');
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('<a></a>');
    downloadLink.attr('href', window.URL.createObjectURL(blob));
    downloadLink.attr('download', filename);
    downloadLink.attr('target', '_blank');  
    document.body.append(downloadLink); 
    downloadLink[0].click(); 
}
Liyosi
fonte
5

Há duas perguntas aqui:

  1. Como converter uma matriz 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 do Milimetric não cobre requisitos alternativos, como cercar cadeias com aspas ou converter matrizes de objetos.

Aqui estão minhas opiniões sobre isso:

Para um csv simples, basta um mapa () e uma junção ():

    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 especificar um separador de colunas que não seja vírgula na junção interna. por exemplo, uma guia:d.join('\t')

Por outro lado, se você quiser fazê-lo corretamente e incluir cadeias entre aspas "", poderá 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 objetos 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, '');
Konstantin
fonte
Se não me engano, acredito que .replacedeve especificar colchetes versus colchetes.
aaronbartell
.replaceé feito em uma cadeia devolvida por values()que leva um objeto e retorna uma matriz de valores
Konstantin
O values()método não foi encontrado quando tentei seu código.
aaronbartell
Obrigado! No Chrome, ele funciona sem chamar values()explicitamente Object. Eu corrigi o exemplo.
Konstantin
5

Muitas soluções de rolagem aqui para converter dados em CSV, mas praticamente todas elas terão várias advertências em termos do tipo de dados que serão formatadas corretamente, sem fazer tropeçar no Excel ou nos gostos.

Por que não usar algo comprovado: Papa Parse

Papa.unparse(data[, config])

Em seguida, basta combinar isso com uma das soluções de download locais aqui, por exemplo. o de @ArneHB parece bom.

John Rix
fonte
4

Função de uma seta no 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 , react-csvexiste para isso

Abdennour TOUMI
fonte
3
A react-csvbiblioteca funciona como um encanto. Ótima solução para quem usa módulos.
Matt Parrilla
Isso falha ao observar o caso em que existem campos dentro do arquivo CSV com vírgulas dentro.
Unpollito 26/09
2

Veja como faço o download de arquivos CSV no lado do cliente no meu aplicativo Java GWT. Agradecimentos especiais a Xavier John por sua solução. Foi verificado que funciona no FF 24.6.0, IE 11.0.20 e Chrome 45.0.2454.99 (64 bits). Espero que isso economize um pouco de tempo para alguém:

public class ExportFile 
{

    private static final String CRLF = "\r\n";

    public static void exportAsCsv(String filename, List<List<String>> data) 
    {
        StringBuilder sb = new StringBuilder();
        for(List<String> row : data) 
        {
            for(int i=0; i<row.size(); i++)
            {
                if(i>0) 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);
            }
        }
    }-*/;
}
Justin Stein
fonte
2

A seguir, é uma solução js nativa.

function export2csv() {
  let data = "";
  const tableData = [];
  const rows = [
    ['111', '222', '333'],
    ['aaa', 'bbb', 'ccc'],
    ['AAA', 'BBB', 'CCC']
  ];
  for (const row of rows) {
    const rowData = [];
    for (const column of row) {
      rowData.push(column);
    }
    tableData.push(rowData.join(","));
  }
  data += tableData.join("\n");
  const a = document.createElement("a");
  a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
  a.setAttribute("download", "data.csv");
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
<button onclick="export2csv()">Export array to csv file</button>

dabeng
fonte
funcionou perfeitamente para mim. obrigado!
Srijani Ghosh
1

Aqui está uma versão amigável do 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)}`);
    }
  };
Chrillewoodz
fonte
1

As respostas acima funcionam, mas lembre-se de que, se você estiver abrindo no formato .xls, as colunas ~~ poderão ser separadas por, em '\t'vez de ',', a resposta https://stackoverflow.com/a/14966131/6169225 funcionou bem para mim, desde que eu usei .join('\t')as matrizes em vez de .join(',').

Marquistador
fonte
funciona bem para arquivos .xls, BTW Eu tenho um pequeno problema, quando o texto é muito longo e excede o tamanho da grade, a planilha não parece muito bem, alguma dica para resolver isso?
GabrielAnzaldo
1

Eu uso essa função para converter um string[][]arquivo CSV. Ele cita uma célula, se 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 quemap seja preenchido com polyfilled.

Nota : Se as células contiverem números, você poderá adicionar cell=''+cellantesif (cell.replace... para converter números em seqüências de caracteres.

Ou você pode escrevê-lo em uma linha usando o ES6:

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

Eu recomendaria o uso de uma biblioteca como o PapaParse: https://github.com/mholt/PapaParse

A resposta aceita atualmente tem vários problemas, incluindo:

  • falha se os dados contiverem uma vírgula
  • falha se os dados contiverem uma quebra de linha
  • (tipo de) falha se os dados contiverem aspas
Falk Tandetzky
fonte
1

Simplesmente tente isso, algumas das respostas aqui não estão tratando dados unicode e dados que possuem vírgula, por exemplo, data.

function downloadUnicodeCSV(filename, datasource) {
    var content = '', newLine = '\r\n';
    for (var _i = 0, datasource_1 = datasource; _i < datasource_1.length; _i++) {
        var line = datasource_1[_i];
        var i = 0;
        for (var _a = 0, line_1 = line; _a < line_1.length; _a++) {
            var item = line_1[_a];
            var it = item.replace(/"/g, '""');
            if (it.search(/("|,|\n)/g) >= 0) {
                it = '"' + it + '"';
            }
            content += (i > 0 ? ',' : '') + it;
            ++i;
        }
        content += newLine;
    }
    var link = document.createElement('a');
    link.setAttribute('href', 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(content));
    link.setAttribute('download', filename);
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
};
imal hasaranga perera
fonte
1

Baixar arquivo CSV

  let csvContent = "data:text/csv;charset=utf-8,";
  rows.forEach(function (rowArray) {
    for (var i = 0, len = rowArray.length; i < len; i++) {
      if (typeof (rowArray[i]) == 'string')
        rowArray[i] = rowArray[i].replace(/<(?:.|\n)*?>/gm, '');
      rowArray[i] = rowArray[i].replace(/,/g, '');
    }

    let row = rowArray.join(",");
    csvContent += row + "\r\n"; // add carriage return
  });
  var encodedUri = encodeURI(csvContent);
  var link = document.createElement("a");
  link.setAttribute("href", encodedUri);
  link.setAttribute("download", "fileName.csv");
  document.body.appendChild(link);
  link.click();
Vik2696
fonte
0

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

html:

<a data-bind="attr: {download: filename, href: csvContent}">Download</a>

ver modelo:

// 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);
Milimétrico
fonte
0

Eu adicionei à função Xavier Johns para incluir também os cabeçalhos de campo, se necessário, mas usa o jQuery. O bit $ .each precisará ser alterado para um loop javascript nativo

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);
        }
    }
}
Bim
fonte
0

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

            JSON Data Ouptut:
             0 :{emails: "SAMPLE Co., [email protected]"}, 1:{emails: "Another CO. , [email protected]"}


            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();
        });
Ronald G
fonte
0

Se você está procurando uma solução realmente rápida, também pode dar uma chance a esta pequena biblioteca que criará e fará o download do arquivo CSV para você: https://github.com/mbrn/filefy

O uso é muito simples:

import { CsvBuilder } from 'filefy';

var csvBuilder = new CsvBuilder("user_list.csv")
  .setColumns(["name", "surname"])
  .addRow(["Eve", "Holt"])
  .addRows([
    ["Charles", "Morris"],
    ["Tracey", "Ramos"]
  ])
  .exportFile();
Mladen Mitrovic
fonte