¿Cómo exportar información de matriz de JavaScript a csv (en el lado del cliente)?

514

Sé que hay muchas preguntas de esta naturaleza, pero necesito hacer esto usando JavaScript. Estoy usando Dojo 1.8y tengo toda la información de atributos en la matriz, que se ve así:

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

¿Alguna idea de cómo puedo exportar esto CSVen el lado del cliente?

Sam007
fuente

Respuestas:

838

Puedes hacer esto en JavaScript nativo. Tendrá que analizar sus datos en el formato CSV correcto como tal (suponiendo que esté utilizando una matriz de matrices para sus datos como ha descrito en la pregunta):

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";
});

o la forma más corta (usando funciones de flecha ):

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

Luego puede usar JavaScript window.openy encodeURIfunciones para descargar el archivo CSV de la siguiente manera:

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

Editar:

Si desea darle a su archivo un nombre específico, debe hacer las cosas de manera un poco diferente, ya que esto no es compatible con el acceso a un URI de datos utilizando el window.openmétodo. Para lograr esto, puede crear un <a>nodo DOM oculto y establecer su downloadatributo de la siguiente manera:

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".
Defecto
fuente
44
Por lo que sé, no hay forma de hacerlo usando window.open. Sin embargo, puede crear un enlace oculto que tenga un downloadatributo establecido para el nombre de archivo que desee. Luego, "haciendo clic" en este enlace descargará el archivo en el nombre que desee, lo agregaré a mi respuesta.
Predeterminado
14
Tuve que agregar document.body.appendChild(link);para obtener soporte completo en FF.
Hardbyte
99
Esta respuesta es incorrecta: fallará para el caso data = [["Hello, world"]]. Eso generará dos columnas cuando debería generar una.
aredridel
18
Esto funciona bien para ~ 7000 filas. Pero comienza a dar este error: NETWORK_INVALID_REQUEST . ¿Alguien más está enfrentando este problema también? ¿Hay algún límite superior de datos sobre la encodeURIComponent()función o algo así? Estoy usando Chrome como navegador.
Abhidemon
13
@Abhidemon La respuesta es que debe usar un tipo de blob para algo tan grande, entonces funcionará bien, por ejemplo: blob = new Blob ([csvContent], {type: "text / csv"}); href = window.URL.createObjectURL (blob); Más detalles: stackoverflow.com/a/19328891/1854079
mdubez
257

Basado en las respuestas anteriores, creé esta función que probé en IE 11, Chrome 36 y 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 ejemplo: https://jsfiddle.net/jossef/m3rrLzk0/

Xavier John
fuente
66
Podría recurrir a window.openuna elsede link.download !== undefined.
MrYellow
2
Este es un buen código. ¿Hay alguna posibilidad de que esté dispuesto a licenciar esto bajo algo más liberal que el SO predeterminado de CC-BY-SA? Por ejemplo, CC0, MIT, BSD, Apache, X11. . . meta.stackexchange.com/questions/12527/…
joseph_morris
1
He estado usando este método para implementar la exportación de Excel en algunas aplicaciones web. Pero Chrome 43+ ahora ha movido los atributos DOM a la cadena de prototipos. Se lanza una excepción a link.style.visibility='hidden'. B / c el atributo DOM es de solo lectura. Se pueden encontrar más detalles en updates.html5rocks.com/2015/04/… en la sección "Escribir en propiedades de solo lectura en modo estricto arrojará un error"
Blaise
1
Esta respuesta es la mejor hasta ahora. Incluye casos con caracteres especiales y paréntesis.
Vladimir Kostov
2
Utilicé la sección de descarga de esta respuesta, y funcionó bien en Chrome, ¡gracias!
Liran H
77

Esta solución debería funcionar con Internet Explorer 10+, Edge, versiones antiguas y nuevas de Chrome, FireFox, Safari, ++

La respuesta aceptada no funcionará con IE y 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');

La ejecución del fragmento de código descargará los datos simulados como csv

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

Arne H. Bitubekk
fuente
1
(Como mínimo, el código HTML5) funciona sin el setTimeout.
StubbornShowaGuy
@StubbornShowaGuy genial, entonces eliminaré el setTimeout del código de ejemplo :)
Arne H. Bitubekk
Funciona en los últimos Chrome, IE y Firefox. ¡Gracias!
walla
La única solución de navegador verdaderamente cruzada aquí. Tenga en cuenta que funciona en Safari 10.10 y Safari móvil. Sin embargo, la iframesección se puede reemplazar solo por location.href = ...
Dan
2
NOTA: Hay un error tipográfico en la función, en realidad es URL.createObjectURL(termina con URLno Url).
Nathan Hinchey
35

Vine aquí buscando un poco más de cumplimiento de RFC 4180 y no pude encontrar una implementación, así que hice una (posiblemente ineficiente) para mis propias necesidades. Pensé en compartirlo con 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');

Esperemos que esto ayude a alguien en el futuro. Esto combina la codificación del CSV junto con la capacidad de descargar el archivo. En mi ejemplo en jsfiddle . Puede descargar el archivo (asumiendo el navegador HTML 5) o ver el resultado en la consola.

ACTUALIZAR:

Chrome ahora parece haber perdido la capacidad de nombrar el archivo. No estoy seguro de qué sucedió o cómo solucionarlo, pero cada vez que uso este código (incluido el jsfiddle), el archivo descargado ahora se llama download.csv.

Uxonith
fuente
Buena captura Chris, no lo
probé
No sé si la última verificación nula es necesariamente un comportamiento esperado. Nulo es muy diferente a una cadena vacía. Si uno fuera a implementar esto, recomendaría un valor nulo personalizado (por ejemplo: '[[NULL]]'). También puede desearse una excepción para indefinido, pero recomendaría no reemplazar nulo con una cadena vacía.
Uxonith
He probado y descubrí que estás en lo correcto. Esto parece funcionar en Chrome y Opera. Safari solo abre una página con el contenido. Internet Explorer ... bueno, es IE. Para mi situación, voy a generar mi servidor CSV y servirlo de esa manera, lamentablemente.
Uxonith
33

La solución de @Default funciona perfectamente en Chrome (¡muchas gracias por eso!) Pero tuve un problema con IE.

Aquí hay una solución (funciona en 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
fuente
23

En la actualización de Chrome 35, se modificó el comportamiento del atributo de descarga.

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

para trabajar esto en Chrome, use esto

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
fuente
1
También puede consultar este: github.com/mholt/PapaParse/issues/175#issuecomment-201308792
Gabriel
¡Esta es la respuesta correcta en este momento, no la marcada como aceptada!
miau
17

Trabajando para todos los 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
fuente
¡Impresionante! (+1) ¡Bienvenido a StackOverflow, amigo!
Rann Lifshitz
¿Pueden ayudarme a comprender qué es ese bloque de código UTF-16 y para qué se utiliza aquí?
Mar1009
Hola mar1009 Esto es necesario para algunos idiomas. Por ejemplo, el alfabeto cirílico.
Serdar Didan
13

Ahí tienes:

<!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
fuente
1
Impresionante respuesta. Estoy votando este porque la respuesta aceptada por alguna razón pone todo en una sola columna. Esto lo divide todo en columnas separadas y el soporte de formato de datos similar a JSON es increíblemente útil.
Hoser
Esto funciona cuando el enlace se agrega por primera vez al cuerpo del documento y luego se hace clic en. Y luego se elimina de dom.
Jay Dubal
1
Buena respuesta, el único inconveniente es que no funciona correctamente cuando los datos tienen un delimitador de columna "," es decir, Dirección: '10 Infinite loop lane, Room 56 ', observe la coma después del carril. Le sugiero que use el enlace PapaParse para convertir los datos a CSV y luego use el método de descarga CSV anterior para la descarga del archivo real
phil
Esto funciona perfecto para mi. Solo tengo un problema, tengo algunos números en la matriz como '000002342' pero cuando se exporta a csv, los ceros iniciales se eliminan. hay alguna forma de prevenir esto?
Aakarsh Dhawan
13

La gente está tratando de crear su propia cadena csv, que falla en casos extremos, por ejemplo, caracteres especiales y demás, seguramente este es un problema resuelto ¿verdad?

papaparse : se usa para la codificación JSON a 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);
  }

}

Ejemplo de uso

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

https://github.com/mholt/PapaParse/issues/175 - Vea este comentario para la discusión de soporte del navegador.

Glen Thompson
fuente
10

Puede usar el siguiente código para exportar la matriz al archivo CSV usando Javascript.

Esto también maneja la parte de caracteres especiales

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

Aquí está el enlace para trabajar jsfiddle

Vignesh Subramanian
fuente
1
La mejor respuesta para personajes especiales
Alejandro
# (hashtag) no funciona!
Nakres
no funciona en Internet Explorer
Danial hace
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
fuente
6

Cree un blob con los datos csv .ie var blob = new Blob([data], type:"text/csv");

Si el navegador admite el almacenamiento de blobs if window.navigator.mSaveOrOpenBlob)===true, es decir , guarde los datos csv usando: window.navigator.msSaveBlob(blob, 'filename.csv')

Si el navegador no admite guardar y abrir blobs, guarde los datos 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);

Fragmento 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
fuente
5

Hay dos preguntas aquí:

  1. Cómo convertir una matriz a una cadena csv
  2. Cómo guardar esa cadena en un archivo

Todas las respuestas a la primera pregunta (excepto la de Milimetric) aquí parecen una exageración. Y el de Milimetric no cubre los requisitos alternativos, como las cadenas circundantes con comillas o la conversión de matrices de objetos.

Aquí están mis opiniones sobre esto:

Para un csv simple, un mapa () y un join () son 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

Este método también le permite especificar un separador de columna que no sea una coma en la unión interna. por ejemplo una pestaña:d.join('\t')

Por otro lado, si desea hacerlo correctamente y encerrar cadenas entre comillas "", puede usar algo de magia 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

si tiene una variedad 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
fuente
Si no me equivoco, creo que .replacedebería especificar entre corchetes y corchetes.
aaronbartell
.replacese realiza en una cadena devuelta por la values()cual toma un objeto y devuelve una matriz de valores
Konstantin
El values()método no se encontró cuando probé su código.
aaronbartell
¡Gracias! En Chrome funciona sin llamar values()explícitamente Object. Corrija el ejemplo.
Konstantin
5

Una gran cantidad de soluciones roll-your-own aquí para convertir datos a CSV, pero casi todas ellas tendrán varias advertencias en términos del tipo de datos que formatearán correctamente sin tropezar con Excel o similares.

¿Por qué no usar algo probado: Papa Parse?

Papa.unparse(data[, config])

Luego simplemente combine esto con una de las soluciones de descarga locales aquí, por ejemplo. el de @ArneHB se ve bien.

John Rix
fuente
4

Una función de flecha con ES6:

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

Entonces :

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

En caso de que alguien necesite esto para , react-csvhay para eso

Abdennour TOUMI
fuente
3
La react-csvbiblioteca funciona a las mil maravillas. Gran solución para cualquiera que use módulos.
Matt Parrilla
Esto no puede observar el caso en el que hay campos dentro del archivo CSV con comas dentro.
unpollito
2

Así es como descargo archivos CSV en el lado del cliente en mi aplicación Java GWT. Un agradecimiento especial a Xavier John por su solución. Se ha verificado que funciona en FF 24.6.0, IE 11.0.20 y Chrome 45.0.2454.99 (64 bits). Espero que esto le ahorre a alguien un poco de tiempo:

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
fuente
2

La siguiente es una solución nativa de js.

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
fuente
Funcionó perfectamente para mí. ¡Gracias!
Srijani Ghosh
1

Aquí hay una versión amigable 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
fuente
1

Las respuestas anteriores funcionan, pero tenga en cuenta que si está abriendo en el formato .xls, las columnas ~~ podrían ~~ estar separadas por, en '\t'lugar de ',', la respuesta https://stackoverflow.com/a/14966131/6169225 funcionó bien para mí, siempre que lo use .join('\t')en las matrices en lugar de .join(',').

Marquistador
fuente
funciona bien para archivos .xls, por cierto, tengo un problema menor, cuando el texto es demasiado largo y excede el tamaño de la cuadrícula, la hoja no se ve muy bien, ¿alguna pista para resolver eso?
gabrielAnzaldo
1

Yo uso esta función para convertir un string[][]archivo a un archivo csv. Cita una celda, si contiene un ", un ,u otro espacio en blanco (excepto espacios en blanco):

/**
 * 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 : no funciona en Internet Explorer <11 a menos que mapse llene de polietileno.

Nota : Si las celdas contienen números, puede agregar cell=''+cellantes if (cell.replace...para convertir números en cadenas.

O puede escribirlo en una línea usando ES6:

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

Recomendaría usar una biblioteca como PapaParse: https://github.com/mholt/PapaParse

La respuesta aceptada actualmente tiene múltiples problemas que incluyen:

  • falla si los datos contienen una coma
  • falla si los datos contienen un salto de línea
  • falla (tipo de) si los datos contienen comillas
Falk Tandetzky
fuente
1

Simplemente intente esto, algunas de las respuestas aquí no están manejando datos Unicode y datos que tienen una coma, por ejemplo, la fecha.

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
fuente
1

Descargar archivo 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
fuente
0

En caso de que alguien necesite esto para knockout js, funciona bien básicamente con la solución propuesta:

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
fuente
0

Agregué a la función Xavier Johns para incluir también los encabezados de campo si es necesario, aunque usa jQuery. Será necesario cambiar el bit $ .each para un bucle de 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
fuente
0

Esta es una respuesta modificada basada en la respuesta aceptada en la que los datos procederían de 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
fuente
0

Si está buscando una solución realmente rápida, también puede darle una oportunidad a esta pequeña biblioteca que creará y descargará el archivo CSV para usted: https://github.com/mbrn/filefy

El uso es muy simple:

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
fuente