如何使用JavaScript从* .CSV文件读取数据?


192

我的csv数据如下所示:

标题1,标题2,标题3,标题4,标题5,值1_1,值2_1,值3_1,值4_1,值5_1,值1_2,值2_2,值3_2,值4_2,值5_2...。

您如何使用Javascript读取此数据并转换为这样的数组?:

[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] ....

我已经尝试过此代码,但是没有运气!:

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

如果CSV文件中没有换行符,那么任何JavaScript代码都将不可能知道一个数组(或对象)在哪里停止而另一个数组在哪里开始(除非您事先知道总是有五个标题)。这是剪切粘贴的监督吗?
Blazemonger,2011年

是的,我事先知道确切有五个字段。
Mahesh Thumar 2011年

1
下一个问题:解决方案中允许使用jQuery吗?您使用了标签,但是示例代码是纯JavaScript。
Blazemonger's

是的,允许使用jQuery,这就是为什么我将其包含在Tag中。
Mahesh Thumar 2011年

1
我认为file://...不允许使用XMLHttpRequest
Noel Llevares 2012年

Answers:


118

注意:在提醒我有效的CSV文件中可能出现的所有“特殊情况”(例如转义引号)之前,我都采用了这种解决方案。我将答案留给那些想要快速又肮脏的东西的人,但我建议使用Evan的答案以确保准确性。


当您的data.txt文件是一串用逗号分隔的长字符串且没有换行符时,此代码将起作用:

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

以下代码将在“真” CSV文件上工作,每组记录之间都有换行符:

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
顺便说一下,这假设CSV文件实际上确实有多行-这就是allText.split(/\r\n|\n/)拆分的内容。如果您的所有数据实际上都是一串用逗号分隔的长字符串,没有换行符,则它不是真正的CSV文件。
Blazemonger,2011年

1
嗨,我已经使用此代码:但是没有输出。仅显示一个空白警报。我的文件如下所示: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 csv.html和data.txt都位于同一文件夹中
Mahesh Thumar

如果这不是正确的文件(或数据),那么我的文件应该是什么样?
Mahesh Thumar 2011年

7
该代码可能无法处理所有有效的IETF标准CSV文件,并且如果存在带有嵌入式逗号,换行符或双引号的字符串,则该代码可能会失败。例如, 1, "IETF allows ""quotes"", commas and \nline breaks"这是允许的,因为字符串用双引号引起来,并且双引号被转义。
2012年

1
我试图从Mac读取.csv文件。当我将第一个拆分更改为this时,我只能使该脚本识别换行符。var allTextLines = allText.split("\r"); 此后效果很好!谢谢!

204

无需自己编写...

jQuery的CSV库有一个调用的函数$.csv.toObjects(csv)是自动完成的映射。

注意:该库旨在处理符合RFC 4180的所有CSV数据,包括大多数“简单”解决方案都忽略的所有讨厌的边缘情况。

就像@Blazemonger已经说过的一样,首先您需要添加换行符以使数据有效为CSV。

使用以下数据集:

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

使用代码:

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

保存在“数据”中的输出将是:

[
  { 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" }
]

注意:从技术上讲,您编写键值映射的方式是无效的JavaScript。包含键值对的对象应放在方括号中。

如果您想自己尝试一下,建议您看一下“ toObjects()”选项卡下的“ 基本用法”演示

免责声明:我是jQuery-CSV的原始作者。

更新:

编辑以使用op提供的数据集,并包括指向演示的链接,在演示中可以测试数据的有效性。

更新2:

由于Google Code的关闭。jquery-csv已移至GitHub


3
IOW,“ toObject”是或可以被认为是“ toJSON”,不是吗?而且,对toObjects(csv)的调用后的冒号是错字吗?IOW,那不是分号吗?
B. Clay Shannon

11
CSV是文件名吗?
泡沫

10
很棒的图书馆。仅供参考,csv传递的参数是csv字符串-以文本形式读取csv文件以获取csv字符串。
callmekatootie 2014年

3
@Evan Plaice如何使用此库从csv文件读取?
Richa Sinha 2015年

1
@RichaSinha通过HTML5 File API或AJAX作为文本缓冲区读取文件。然后将字符串缓冲区传递到解析器。结果将吐出数据数组。有关示例,请参见项目页面。
Evan Plaice 2015年

75

请不要用逗号分隔-它不适用于大多数CSV文件,而且对于提问者的输入数据而言,这个问题的观点太多了,无法应用于所有人。解析CSV有点吓人,因为还没有真正的官方标准,而且许多带分隔符的文本编写者都没有考虑极端情况。

这个问题很古老,但是我相信,有了Papa Parse,现在有了更好的解决方案。这是我在贡献者的帮助下编写的一个库,用于解析CSV文本或文件。这是我所知道的唯一一个支持千兆字节文件的JS库。它还可以优雅地处理格式错误的输入。

1分钟内解析出1 GB文件: 1分钟内解析1 GB文件

更新:使用Papa Parse 4,同一文件在Firefox中仅花费了大约30秒。PapaParse 4现在是浏览器中已知最快的CSV解析器。)

解析文本非常简单:

var data = Papa.parse(csvString);

解析文件也很容易:

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

流文件类似(这是流远程文件的示例):

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

如果您的网页在解析过程中被锁定,Papa可以使用Web Worker使您的网站保持被动状态。

如果存在标题行,Papa可以自动检测定界符并与标题列匹配值。它还可以将数值转换为实际的数字类型。它可以适当地分析换行符和引号以及其他怪异的情况,甚至可以尽可能可靠地处理格式错误的输入。我从现有库中汲取了灵感来制作Papa,因此成为其他JS实现的支撑。


爸爸很容易使用并且快速!谢谢!
Technotronic

+1在Papa Parse上干得不错。我希望有一天能详细研究它,看看您如何处理大文件和流媒体。我很高兴看到其他开发人员编写功能齐全的解析器,这些解析器可以在jquery-csv停止的地方继续使用。
埃文·普赖斯

3
@EvanPlaice谢谢。您可能会喜欢我昨晚在一次本地聚会上发表的演讲:docs.google.com/presentation/d/…–
马特

1
@ Matt这真是一个很棒的演讲,它以更多的理解方式描述了爸爸的解析
siva 2015年

1
@ Malky.Kid无效的CSV(即,无分隔值的空格不好)。MS Excel的CSV格式实现很糟糕。如果您仍然有权访问源文件,则应该有一个启用引号定界符的选项。完成此操作后,您的数据应可与任何csv解析器一起使用。
伊万·普赖斯

9

我正在使用d3.js解析csv文件。很好用。这是文档

脚步:

  • npm install d3-request

使用Es6;

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

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

请参阅文档以获取更多信息。

更新 -d3请求已弃用。您可以使用d3-fetch



3

这是一个JavaScript函数,用于解析CSV数据,并计算引号内的逗号。

// 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;                                                      
}

函数使用示例来解析如下所示的CSV文件的示例:

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

分成数组:

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

这是将数据转换为对象的方法,例如D3的csv解析器(这是可靠的第三方解决方案):

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

是这段代码工作提琴

请享用!- 库伦


1

这是将外部CSV读入Javascript(使用jQuery)的另一种方法。

这有点冗长,但是我觉得通过将数据读入数组,您可以完全按照流程进行操作,并且可以轻松地进行故障排除。

可能会帮助别人。

数据文件示例:

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

这是代码:

$(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]);
    }
})

希望这对以后的人有所帮助!


您好,从将来开始,所以我尝试了这个答案,并且)在第45行缺少一个标志,所以我添加了它,但是现在在第9行,这给了我一个控制台错误,Uncaught ReferenceError: $ is not defined at index.html:9您能帮忙吗?
烤宽面条猫

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

我喜欢让正则表达式尽可能多地执行。此正则表达式将所有项目视为带引号或不带引号的,后跟列定界符或行定界符。或文字结尾。

这就是最后一个条件的原因-没有它,它将是一个无限循环,因为该模式可以匹配零长度字段(在csv中完全有效)。但是由于$是一个零长度的断言,它不会前进到不匹配并结束循环。

仅供参考,我不得不做出第二种选择,排除围绕该值的引号;似乎它是在我的JavaScript引擎上的第一个替代方法之前执行的,并将引号视为未引号值的一部分。我不会问-只是让它起作用。


不幸的是,我使用此功能陷入了无限循环。
Hauke

@Hauke-如果您可以将数据分解为仍然会产生无限循环的几行和几行,我将不胜感激-它可以让我深入了解以前为什么会失败。
杰拉德·奥尼尔

1

根据公认的答案

我通过将1更改为0来使它起作用:

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

变成

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

它将计算一个文件,该文件具有一个连续行,且allTextLines.length为1。因此,如果循环从1开始并一直运行(只要循环小于1),它将永远不会运行。因此,空白警报框。


0

如果要在不使用Ajax的情况下解决此问题,请使用FileReader()Web API

示例实现:

  1. 选择 .csv档案
  2. 查看输出

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

                        }
                      }
                    }

尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。来自评论
双响
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.