Come leggere i dati dal file * .CSV usando javascript?


196

I miei dati CSV si presentano così:

Titolo 1, Titolo2, Titolo 3, heading4, heading5, value1_1, value2_1, value3_1, value4_1, value5_1, value1_2, value2_2, value3_2, value4_2, value5_2 ....

Come leggi questi dati e li converti in un array come questo usando Javascript ?:

[titolo1: valore1_1, titolo2: valore2_1, titolo3: valore3_1, titolo4: valore4_1, titolo5: valore5_1], [titolo1: valore1_2, titolo2: valore2_2, titolo3: valore3_2, titolo4: valore4_2, titolo5: valore5_2] ....

Ho provato questo codice ma senza fortuna !:

<script type="text/javascript">
    var allText =[];
    var allTextLines = [];
    var Lines = [];

    var txtFile = new XMLHttpRequest();
    txtFile.open("GET", "file://d:/data.txt", true);
    txtFile.onreadystatechange = function()
    {
        allText = txtFile.responseText;
        allTextLines = allText.split(/\r\n|\n/);
    };

    document.write(allTextLines);<br>
    document.write(allText);<br>
    document.write(txtFile);<br>
</script>

Senza interruzioni di riga nel file CSV, sarà impossibile per qualsiasi codice JavaScript sapere dove si ferma un array (o oggetto) e inizia l'altro (a meno che non si sappia in anticipo che ci sono sempre esattamente cinque intestazioni). È stata una svista incisiva?
Blazemonger,

Sì, so in anticipo che ci sono esattamente cinque campi.
Mahesh Thumar,

1
Domanda successiva: jQuery è consentito nella soluzione? Hai usato il tag ma il tuo codice di esempio è puro JavaScript.
Blazemonger,

sì, jQuery è consentito, ecco perché lo includo in Tag.
Mahesh Thumar,

1
Non credo file://...sia consentito l'uso diXMLHttpRequest .
Noel Llevares,

Risposte:


118

NOTA: ho inventato questa soluzione prima di essere ricordato di tutti i "casi speciali" che possono verificarsi in un file CSV valido, come virgolette di escape. Lascio la mia risposta a coloro che vogliono qualcosa di veloce e sporco, ma raccomando la risposta di Evan per la precisione.


Questo codice funzionerà quando il tuo data.txtfile è una lunga stringa di voci separate da virgola, senza nuove righe:

data.txt:

 heading1,heading2,heading3,heading4,heading5,value1_1,...,value5_2

javascript:

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

function processData(allText) {
    var record_num = 5;  // or however many elements there are in each row
    var allTextLines = allText.split(/\r\n|\n/);
    var entries = allTextLines[0].split(',');
    var lines = [];

    var headings = entries.splice(0,record_num);
    while (entries.length>0) {
        var tarr = [];
        for (var j=0; j<record_num; j++) {
            tarr.push(headings[j]+":"+entries.shift());
        }
        lines.push(tarr);
    }
    // alert(lines);
}

Il codice seguente funzionerà su un file CSV "vero" con interruzioni di riga tra ogni set di record:

data.txt:

heading1,heading2,heading3,heading4,heading5
value1_1,value2_1,value3_1,value4_1,value5_1
value1_2,value2_2,value3_2,value4_2,value5_2

javascript:

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

function processData(allText) {
    var allTextLines = allText.split(/\r\n|\n/);
    var headers = allTextLines[0].split(',');
    var lines = [];

    for (var i=1; i<allTextLines.length; i++) {
        var data = allTextLines[i].split(',');
        if (data.length == headers.length) {

            var tarr = [];
            for (var j=0; j<headers.length; j++) {
                tarr.push(headers[j]+":"+data[j]);
            }
            lines.push(tarr);
        }
    }
    // alert(lines);
}

http://jsfiddle.net/mblase75/dcqxr/


4
A proposito, questo presuppone che il file CSV abbia in realtà più righe - ecco cosa si allText.split(/\r\n|\n/)divide. Se tutti i tuoi dati sono in realtà una lunga stringa di dati separati da virgola senza nuove righe, non è un vero file CSV.
Blazemonger,

1
Ciao ho usato questo codice: ma non c'è output. Viene visualizzato solo un avviso vuoto. il mio file è simile a: titolo1, titolo2, titolo3, titolo4, titolo5, valore1_1, valore2_1, valore3_1, valore4_1, valore5_1, valore1_2, valore2_2, valore3_2, valore4_2, valore5_2 Entrambi csv.html e data.txt sono nella stessa cartella
Mahesh Thumar

Se questo non è un file (o dati) corretto, come dovrebbe essere il mio file ??
Mahesh Thumar,

7
Il codice potrebbe non gestire tutti i file CSV standard IETF validi e potrebbe non riuscire se sono presenti stringhe con virgole incorporate, interruzioni di riga o virgolette doppie. Ad esempio, 1, "IETF allows ""quotes"", commas and \nline breaks"ciò è consentito poiché la stringa è racchiusa tra virgolette doppie e le virgolette doppie sono salvate.
prototipo

1
Stavo cercando di leggere un file .csv da un mac. Sono stato in grado di ottenere questo script per riconoscere i caratteri di nuova riga quando ho cambiato la prima divisione in questo var allTextLines = allText.split("\r"); Dopo che ha funzionato alla grande! Grazie!
Joe,

207

Non c'è bisogno di scrivere il tuo ...

La libreria jQuery-CSV ha una funzione chiamata $.csv.toObjects(csv)che esegue automaticamente la mappatura.

Nota: la libreria è progettata per gestire tutti i dati CSV conformi a RFC 4180 , inclusi tutti i casi limite che la maggior parte delle soluzioni "semplici" trascurano.

Come già affermato da @Blazemonger, per prima cosa è necessario aggiungere interruzioni di riga per rendere validi i dati CSV.

Utilizzando il seguente set di dati:

heading1,heading2,heading3,heading4,heading5
value1_1,value2_1,value3_1,value4_1,value5_1
value1_2,value2_2,value3_2,value4_2,value5_2

Usa il codice:

var data = $.csv.toObjects(csv):

L'output salvato in "dati" sarà:

[
  { heading1:"value1_1",heading2:"value2_1",heading3:"value3_1",heading4:"value4_1",heading5:"value5_1" } 
  { heading1:"value1_2",heading2:"value2_2",heading3:"value3_2",heading4:"value4_2",heading5:"value5_2" }
]

Nota: tecnicamente, il modo in cui hai scritto la mappatura dei valori-chiave non è JavaScript valido. Gli oggetti contenenti le coppie chiave-valore devono essere racchiusi tra parentesi.

Se vuoi provarlo tu stesso, ti suggerisco di dare un'occhiata alla Dimostrazione d'uso di base nella scheda 'toObjects ()'.

Disclaimer: sono l'autore originale di jQuery-CSV.

Aggiornare:

Modificato per utilizzare il set di dati fornito dall'operazione e incluso un collegamento alla demo in cui è possibile verificare la validità dei dati.

Update2:

A causa della chiusura del codice di Google. jquery-csv è passato a GitHub


3
IOW, "toObject" è o può essere pensato come "toJSON", no? E i due punti dopo la chiamata a toObjects (csv) è un refuso? IOW, non dovrebbe essere un punto e virgola?
B. Clay Shannon,

11
CSV è un nome file?
bolla

10
Biblioteca fantastica. Cordiali saluti, il parametro csvpassato è una stringa CSV: leggi il file CSV come testo per ottenere la stringa CSV.
Callmekatootie,

3
@Evan Plaice Come usare questa libreria per leggere da un file CSV?
Richa Sinha,

1
@RichaSinha Leggi il file come buffer di testo tramite l'API File HTML5 o AJAX. Quindi passare il buffer delle stringhe nel parser. Di conseguenza sputerà una serie di dati. Vedi la pagina del progetto per esempi.
Evan Plaice,

75

Non dividere le virgole: non funzionerà per la maggior parte dei file CSV e questa domanda ha troppe visualizzazioni per il tipo di dati di input del richiedente da applicare a tutti. Analizzare CSV è un po 'spaventoso poiché non esiste uno standard veramente ufficiale e molti scrittori di testi delimitati non prendono in considerazione casi limite.

Questa domanda è vecchia, ma credo che ci sia una soluzione migliore ora che Papa Parse è disponibile. È una libreria che ho scritto, con l'aiuto di collaboratori, che analizza testo o file CSV. È l'unica libreria JS che conosco che supporta file di dimensioni gigabyte. Gestisce anche in modo corretto input non validi.

File da 1 GB analizzato in 1 minuto: Analizzato file da 1 GB in 1 minuto

( Aggiornamento: con Papa Parse 4, lo stesso file ha impiegato solo circa 30 secondi in Firefox. Papa Parse 4 è ora il parser CSV più veloce conosciuto per il browser.)

L'analisi del testo è molto semplice:

var data = Papa.parse(csvString);

Anche l'analisi dei file è semplice:

Papa.parse(file, {
    complete: function(results) {
        console.log(results);
    }
});

Lo streaming di file è simile (ecco un esempio che esegue lo streaming di un file remoto):

Papa.parse("http://example.com/bigfoo.csv", {
    download: true,
    step: function(row) {
        console.log("Row:", row.data);
    },
    complete: function() {
        console.log("All done!");
    }
});

Se la tua pagina web si blocca durante l'analisi, Papà può usare i web worker per mantenere reattivo il tuo sito web.

Papa può rilevare automaticamente i delimitatori e far corrispondere i valori con le colonne di intestazione, se è presente una riga di intestazione. Può anche trasformare valori numerici in tipi di numeri reali. Analizza in modo appropriato le interruzioni di riga e le virgolette e altre situazioni strane e gestisce anche input non validi nel modo più affidabile possibile. Ho tratto ispirazione dalle librerie esistenti per creare Papa, quindi propongo altre implementazioni di JS.


Papa è facile da usare e veloce! Grazie!
Technotronic,

+1 Ottimo lavoro su Papa Parse. Mi piacerebbe studiarlo in dettaglio un giorno per vedere come hai gestito file di grandi dimensioni e streaming. Sono molto felice di vedere altri sviluppatori che scrivono parser con funzionalità complete che riprendono da dove si era interrotto jquery-csv.
Evan Plaice,

3
@EvanPlaice Grazie. Potrebbe piacerti questa presentazione che ho fatto ieri sera a un incontro locale: docs.google.com/presentation/d/…
Matt

1
@ Matt Questa è stata una presentazione fantastica che descrive papà parse in modo più comprensivo
siva,

1
@ Malky.Kid Questo non è CSV valido (ovvero gli spazi in un valore non delimitato non sono buoni). L'implementazione del formato CSV di MS Excel fa schifo. Se hai ancora accesso al file di origine, dovrebbe esserci un'opzione per abilitare i delimitatori di preventivo. Una volta fatto ciò, i tuoi dati dovrebbero funzionare con qualsiasi parser CSV.
Evan Plaice,

10

Sto usando d3.js per l'analisi del file CSV. Molto facile da usare Ecco i documenti .

passi:

  • npm installa d3-request

Usando Es6;

import { csv } from 'd3-request';
import url from 'path/to/data.csv';

csv(url, function(err, data) {
 console.log(data);
})

Consulta i documenti per ulteriori informazioni.

Aggiornamento: la richiesta d3 è obsoleta. puoi usare d3-fetch



3

Ecco una funzione JavaScript che analizza i dati CSV, tenendo conto delle virgole trovate tra virgolette.

// Parse a CSV row, accounting for commas inside quotes                   
function parse(row){
  var insideQuote = false,                                             
      entries = [],                                                    
      entry = [];
  row.split('').forEach(function (character) {                         
    if(character === '"') {
      insideQuote = !insideQuote;                                      
    } else {
      if(character == "," && !insideQuote) {                           
        entries.push(entry.join(''));                                  
        entry = [];                                                    
      } else {
        entry.push(character);                                         
      }                                                                
    }                                                                  
  });
  entries.push(entry.join(''));                                        
  return entries;                                                      
}

Esempio di utilizzo della funzione per analizzare un file CSV simile al seguente:

"foo, the column",bar
2,3
"4, the value",5

in array:

// csv could contain the content read from a csv file
var csv = '"foo, the column",bar\n2,3\n"4, the value",5',

    // Split the input into lines
    lines = csv.split('\n'),

    // Extract column names from the first line
    columnNamesLine = lines[0],
    columnNames = parse(columnNamesLine),

    // Extract data from subsequent lines
    dataLines = lines.slice(1),
    data = dataLines.map(parse);

// Prints ["foo, the column","bar"]
console.log(JSON.stringify(columnNames));

// Prints [["2","3"],["4, the value","5"]]
console.log(JSON.stringify(data));

Ecco come puoi trasformare i dati in oggetti, come il parser csv di D3 (che è una solida soluzione di terze parti):

var dataObjects = data.map(function (arr) {
  var dataObject = {};
  columnNames.forEach(function(columnName, i){
    dataObject[columnName] = arr[i];
  });
  return dataObject;
});

// Prints [{"foo":"2","bar":"3"},{"foo":"4","bar":"5"}]
console.log(JSON.stringify(dataObjects));

Ecco un violino funzionante di questo codice .

Godere! - Curran


1

Ecco un altro modo per leggere un CSV esterno in Javascript (usando jQuery).

È un po 'più lungo, ma sento che leggendo i dati in array puoi seguire esattamente il processo e facilitare la risoluzione dei problemi.

Potrebbe aiutare qualcun altro.

L'esempio del file di dati:

Time,data1,data2,data2
08/11/2015 07:30:16,602,0.009,321

Ed ecco il codice:

$(document).ready(function() {
 // AJAX in the data file
    $.ajax({
        type: "GET",
        url: "data.csv",
        dataType: "text",
        success: function(data) {processData(data);}
        });

    // Let's process the data from the data file
    function processData(data) {
        var lines = data.split(/\r\n|\n/);

        //Set up the data arrays
        var time = [];
        var data1 = [];
        var data2 = [];
        var data3 = [];

        var headings = lines[0].split(','); // Splice up the first row to get the headings

        for (var j=1; j<lines.length; j++) {
        var values = lines[j].split(','); // Split up the comma seperated values
           // We read the key,1st, 2nd and 3rd rows 
           time.push(values[0]); // Read in as string
           // Recommended to read in as float, since we'll be doing some operations on this later.
           data1.push(parseFloat(values[1])); 
           data2.push(parseFloat(values[2]));
           data3.push(parseFloat(values[3]));

        }

    // For display
    var x= 0;
    console.log(headings[0]+" : "+time[x]+headings[1]+" : "+data1[x]+headings[2]+" : "+data2[x]+headings[4]+" : "+data2[x]);
    }
})

Spero che questo aiuti qualcuno in futuro!


Ciao dal futuro, quindi ho provato questa risposta e mancava un )segno alla riga 45, quindi l'ho aggiunto, ma ora alla riga 9 mi sta dando un errore di console Uncaught ReferenceError: $ is not defined at index.html:9Potresti aiutarti in questo?
Lasagna Cat

1
function CSVParse(csvFile)
{
    this.rows = [];

    var fieldRegEx = new RegExp('(?:\s*"((?:""|[^"])*)"\s*|\s*((?:""|[^",\r\n])*(?:""|[^"\s,\r\n]))?\s*)(,|[\r\n]+|$)', "g");   
    var row = [];
    var currMatch = null;

    while (currMatch = fieldRegEx.exec(this.csvFile))
    {
        row.push([currMatch[1], currMatch[2]].join('')); // concatenate with potential nulls

        if (currMatch[3] != ',')
        {
            this.rows.push(row);
            row = [];
        }

        if (currMatch[3].length == 0)
            break;
    }
}

Mi piace che il regex faccia il più possibile. Questa regex considera tutti gli elementi come quotati o non quotati, seguiti da un delimitatore di colonna o da un delimitatore di riga. O la fine del testo.

Ecco perché quest'ultima condizione - senza di essa sarebbe un ciclo infinito poiché il modello può corrispondere a un campo di lunghezza zero (totalmente valido in CSV). Ma poiché $ è un'asserzione di lunghezza zero, non passerà a una non corrispondenza e terminerà il ciclo.

E Cordiali saluti, ho dovuto fare in modo che la seconda alternativa escludesse le virgolette che circondavano il valore; sembra che fosse in esecuzione prima della prima alternativa sul mio motore javascript e considerando le virgolette come parte del valore non quotato. Non chiederò - ho appena funzionato.


Sfortunatamente sono entrato in un ciclo infinito con questa funzione.
Hauke,

@Hauke ​​- se potessi suddividere i dati in un paio di colonne e righe che producono ancora il ciclo infinito, lo apprezzerei - potrebbe darmi un'idea del perché non stavo fallendo prima.
Gerard ONeill,

1

Per la risposta accettata ,

Ho fatto funzionare questo cambiando l'1 in uno qui:

for (var i=1; i<allTextLines.length; i++) {

cambiato in

for (var i=0; i<allTextLines.length; i++) {

Calcolerà un file con una linea continua come avente un valore allTextLines.length di 1. Quindi, se il ciclo inizia da 1 e funziona finché è inferiore a 1, non viene mai eseguito. Da qui la casella di avviso vuota.


0

Se vuoi risolverlo senza usare Ajax , usa l' FileReader()API Web .

Esempio di implementazione:

  1. Seleziona il .csvfile
  2. Vedi output

function readSingleFile(e) {
  var file = e.target.files[0];
  if (!file) {
    return;
  }

  var reader = new FileReader();
  reader.onload = function(e) {
    var contents = e.target.result;
    displayContents(contents);
    displayParsed(contents);
  };
  reader.readAsText(file);
}

function displayContents(contents) {
  var element = document.getElementById('file-content');
  element.textContent = contents;
}

function displayParsed(contents) {
  const element = document.getElementById('file-parsed');
  const json = contents.split(',');
  element.textContent = JSON.stringify(json);
}

document.getElementById('file-input').addEventListener('change', readSingleFile, false);
<input type="file" id="file-input" />

<h3>Raw contents of the file:</h3>
<pre id="file-content">No data yet.</pre>

<h3>Parsed file contents:</h3>
<pre id="file-parsed">No data yet.</pre>


0
$(function() {

      $("#upload").bind("click", function() {
            var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.xlsx)$/;
            if (regex.test($("#fileUpload").val().toLowerCase())) {
              if (typeof(FileReader) != "undefined") {
                var reader = new FileReader();
                reader.onload = function(e) {
                    var customers = new Array();
                    var rows = e.target.result.split("\r\n");
                    for (var i = 0; i < rows.length - 1; i++) {
                      var cells = rows[i].split(",");
                      if (cells[0] == "" || cells[0] == undefined) {
                        var s = customers[customers.length - 1];
                        s.Ord.push(cells[2]);
                      } else {
                        var dt = customers.find(x => x.Number === cells[0]);
                        if (dt == undefined) {
                          if (cells.length > 1) {
                            var customer = {};
                            customer.Number = cells[0];
                            customer.Name = cells[1];
                            customer.Ord = new Array();

                            customer.Ord.push(cells[2]);
                            customer.Point_ID = cells[3];
                            customer.Point_Name = cells[4];
                            customer.Point_Type = cells[5];
                            customer.Set_ORD = cells[6];
                            customers.push(customer);
                          }
                        } else {
                          var dtt = dt;
                          dtt.Ord.push(cells[2]);

                        }
                      }
                    }

Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolva il problema, contribuirebbe davvero a migliorare la qualità del tuo post e probabilmente darebbe più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo per la persona che chiede ora. Si prega di modificare la risposta per aggiungere spiegazioni e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni. Dalla recensione
Doppio segnale acustico

0

In realtà puoi usare una libreria leggera chiamata any-text .

  • installare dipendenze
npm i -D any-text
  • usa il comando personalizzato per leggere i file
var reader = require('any-text');
 
reader.getText(`path-to-file`).then(function (data) {
  console.log(data);
});

o usa async-waitit:

var reader = require('any-text');
 
const chai = require('chai');
const expect = chai.expect;
 
describe('file reader checks', () => {
  it('check csv file content', async () => {
    expect(
      await reader.getText(`${process.cwd()}/test/files/dummy.csv`)
    ).to.contains('Lorem ipsum');
  });
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.