Exportieren Sie Javascript-Daten ohne Serverinteraktion in eine CSV-Datei

77

Wenn wir auf einem NodeJS-Server wären, könnten wir einen Header schreiben, einen MIME-Typ festlegen und ihn senden:

res.header("Content-Disposition", "attachment;filename="+name+".csv"); 
res.type("text/csv");
res.send(200, csvString);

Aufgrund der Header erstellt der Browser einen Download für die genannte CSV-Datei.

Wenn nützliche Daten in einem Browser generiert werden, besteht eine Lösung, um sie in eine CSV-Datei aufzunehmen, darin, Ajax zu verwenden, sie auf den Server hochzuladen (möglicherweise optional dort zu speichern) und den Server zu veranlassen, sie mit diesen Headern zurückzusenden, um a zu werden CSV-Download wieder im Browser.

Ich möchte jedoch eine 100% ige Browserlösung, die kein Ping-Pong mit dem Server beinhaltet.

So kam mir der Gedanke, dass man ein neues Fenster öffnen und versuchen könnte, den Header mit einem META-Tag-Äquivalent zu setzen.

In den letzten Chrome-Versionen funktioniert dies jedoch nicht.

Ich bekomme ein neues Fenster, das den csvString enthält, aber nicht als Download fungiert.

Ich denke, ich habe erwartet, dass ich entweder einen Download in einem unteren Tab oder ein leeres neues Fenster mit einem Download in einem unteren Tab bekomme.

Ich frage mich, ob die Meta-Tags korrekt sind oder ob auch andere Tags benötigt werden.

Gibt es eine Möglichkeit, dies zum Laufen zu bringen, ohne es auf den Server zu übertragen?

JsFiddle zum Erstellen einer CSV im Browser (funktioniert nicht - Ausgabefenster, aber kein Download)

var A = [['n','sqrt(n)']];  // initialize array of rows with header row as 1st item
for(var j=1;j<10;++j){ A.push([j, Math.sqrt(j)]) }
var csvRows = [];
for(var i=0,l=A.length; i<l; ++i){
    csvRows.push(A[i].join(','));   // unquoted CSV row
}
var csvString = csvRows.join("\n");
console.log(csvString);
var csvWin = window.open("","","");
csvWin.document.write('<meta name="content-type" content="text/csv">');
csvWin.document.write('<meta name="content-disposition" content="attachment;  filename=data.csv">  ');
csvWin.document.write(csvString);
Paul
quelle
1
Vielleicht hilft das: stackoverflow.com/questions/6796974/…
Vengarioth
@Vengarioth Daten-URLs sind sicherlich dunkel genug, um eine Möglichkeit zu sein. Es ist sicherlich nicht offensichtlich, ich habe keine Bibliothek gesehen, die dies tut, und eine andere Antwort aus dem Jahr 2011 besagt, dass dies nicht möglich ist.
Paul
Ähnliche Daten-URL-Tricks werden von @Italo an stackoverflow.com/questions/4639372/export-to-csv-in-jquery
Paul

Antworten:

161

Es gibt immer das HTML5- downloadAttribut:

Wenn dieses Attribut vorhanden ist, gibt der Autor an, dass der Hyperlink zum Herunterladen einer Ressource verwendet werden soll. Wenn der Benutzer auf den Link klickt, wird er aufgefordert, ihn als lokale Datei zu speichern.

Wenn das Attribut einen Wert hat, wird der Wert als vorgefüllter Dateiname in der Eingabeaufforderung Speichern verwendet, die geöffnet wird, wenn der Benutzer auf den Link klickt.

var A = [['n','sqrt(n)']];

for(var j=1; j<10; ++j){ 
    A.push([j, Math.sqrt(j)]);
}

var csvRows = [];

for(var i=0, l=A.length; i<l; ++i){
    csvRows.push(A[i].join(','));
}

var csvString = csvRows.join("%0A");
var a         = document.createElement('a');
a.href        = 'data:attachment/csv,' +  encodeURIComponent(csvString);
a.target      = '_blank';
a.download    = 'myFile.csv';

document.body.appendChild(a);
a.click();

GEIGE

In Chrome und Firefox getestet, funktioniert in den neuesten Versionen (Stand Juli 2013) einwandfrei .
Funktioniert auch in Opera, legt jedoch den Dateinamen nicht fest (Stand Juli 2013) .
Scheint in IE9 nicht zu funktionieren (große Überraschung) (Stand Juli 2013) .

Eine Übersicht darüber, welche Browser das Download-Attribut unterstützen, finden Sie hier.
Bei nicht unterstützten Browsern müssen die entsprechenden Header auf der Serverseite festgelegt werden.


Anscheinend gibt es einen Hack für IE10 und IE11 , der das downloadAttribut nicht unterstützt (Edge jedoch) .

var A = [['n','sqrt(n)']];

for(var j=1; j<10; ++j){ 
    A.push([j, Math.sqrt(j)]);
}

var csvRows = [];

for(var i=0, l=A.length; i<l; ++i){
    csvRows.push(A[i].join(','));
}

var csvString = csvRows.join("%0A");

if (window.navigator.msSaveOrOpenBlob) {
    var blob = new Blob([csvString]);
    window.navigator.msSaveOrOpenBlob(blob, 'myFile.csv');
} else {
    var a         = document.createElement('a');
    a.href        = 'data:attachment/csv,' +  encodeURIComponent(csvString);
    a.target      = '_blank';
    a.download    = 'myFile.csv';
    document.body.appendChild(a);
    a.click();
}
Adeneo
quelle
2
Ich konnte nicht herausfinden, wie ich einen Dateinamen festlegen soll, aber ich bin mir sicher, dass dies irgendwie möglich ist. Es ist normalerweise, attachment;filename=somefile.csvaber das scheint nicht für CSV-Strings zu funktionieren?
Adeneo
19
a.href = 'Daten: Anhang / csv' + encodeURIComponent (csvString);
Paul
1
Ich vermute, sie könnten wieder in die eigentliche Datei konvertiert werden ... aber nicht sicher
Paul
1
Der Dateiname hat bei mir in Chrome nicht funktioniert. Es hat funktioniert, als ich a.href in Folgendes geändert habe: a.href = window.URL.createObjectURL (neuer Blob ([csvString], {Typ: "Anhang / csv"}));
Facio Ratio
1
@FacioRatio Google hat in Chrome etwas geändert. Unterbrechen der Fähigkeit, den Dateinamen festzulegen. Siehe: code.google.com/p/chromium/issues/detail?id=373182
Paul
31

@adeneo Antwort funktioniert für Firefox und Chrome ... Für IE kann das Folgende verwendet werden.

if (window.navigator.msSaveOrOpenBlob) {
  var blob = new Blob([decodeURIComponent(encodeURI(result.data))], {
    type: "text/csv;charset=utf-8;"
  });
  navigator.msSaveBlob(blob, 'FileName.csv');
}

Manu Sharma
quelle
3
Ich kann bestätigen, dass dies in IE11 funktioniert, und habe meine Bibliothek html5csv aktualisiert , um IE 11-Unterstützung basierend auf dieser Technik einzuschließen . Ich habe Ihren Beitrag in den Codekommentaren gutgeschrieben. Vielen Dank.
Paul
15

Siehe Adeneos Antwort, aber vergiss nicht encodeURIComponent!

a.href     = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csvString);

Außerdem musste ich "\ r \ n" und nicht nur "\ n" für das Zeilentrennzeichen ausführen.

var csvString = csvRows.join("\r\n");

Überarbeitete Geige: http://jsfiddle.net/7Q3c6/

user2608223
quelle
7

Nachdem ich JS-Code in eine winzige Bibliothek gepackt hatte:

https://github.com/AlexLibs/client-side-csv-generator

Der Code, die Dokumentation und die Demo / der Spielplatz werden auf Github bereitgestellt.

Genießen :)

Pull-Anfragen sind willkommen.

Alexander
quelle
2

Siehe die Antwort von Adeneo, aber damit dies in Excel in allen Ländern funktioniert, sollten Sie der ersten Zeile der Datei "SEP =" hinzufügen. Dadurch wird das Standardtrennzeichen in Excel festgelegt und nicht im eigentlichen Dokument angezeigt

var csvString = "SEP=, \n" + csvRows.join("\r\n");
Thyselius
quelle
Ich bezweifle, dass R oder Pandas (Python) das in einer CSV-Datei mögen werden.
Paul
1
@Paul Das mag wahr sein, aber in meinem Fall musste ich eine CSV-Datei erstellen, um sie in Excel zu öffnen, und ich möchte, dass sie unabhängig von der Lokalität auf präsentable Weise geöffnet wird. Wenn Sie eine bessere Lösung dafür haben, würde ich es gerne hören!
Thyselius
1

Wir können die Excel-Datei einfach mit jedem Trennzeichen (in dieser Antwort verwende ich das Komma-Trennzeichen) mithilfe von Javascript erstellen und exportieren / herunterladen. Ich verwende kein externes Paket zum Erstellen der Excel-Datei.

    var Head = [[
        'Heading 1',
        'Heading 2', 
        'Heading 3', 
        'Heading 4'
    ]];

    var row = [
       {key1:1,key2:2, key3:3, key4:4},
       {key1:2,key2:5, key3:6, key4:7},
       {key1:3,key2:2, key3:3, key4:4},
       {key1:4,key2:2, key3:3, key4:4},
       {key1:5,key2:2, key3:3, key4:4}
    ];

for (var item = 0; item < row.length; ++item) {
       Head.push([
          row[item].key1,
          row[item].key2,
          row[item].key3,
          row[item].key4
       ]);
}

var csvRows = [];
for (var cell = 0; cell < Head.length; ++cell) {
       csvRows.push(Head[cell].join(','));
}
            
var csvString = csvRows.join("\n");
let csvFile = new Blob([csvString], { type: "text/csv" });
let downloadLink = document.createElement("a");
downloadLink.download = 'MYCSVFILE.csv';
downloadLink.href = window.URL.createObjectURL(csvFile);
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
downloadLink.click();

Pulkit Aggarwal
quelle