繁体   English   中英

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

[英]How to read data From *.CSV file using JavaScript?

我的 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
...

如何使用 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);
    document.write(allText);
    document.write(txtFile);
</script>

不用自己写...

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 的原作者。

更新:

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

更新2:

由于谷歌代码的关闭。 jquery-csv 已移至 GitHub

注意:在提醒我有效 CSV 文件中可能出现的所有“特殊情况”(如转义引号)之前,我编写了此解决方案。 我将把我的答案留给那些想要快速和肮脏的人,但我推荐Evan 的答案以确保准确性。


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

数据.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 文件:

数据.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/

不要以逗号分隔 - 它不适用于大多数 CSV 文件,而且这个问题对于提问者的输入数据类型有太多视图,无法应用于每个人。 解析 CSV 有点吓人,因为没有真正的官方标准,而且许多分隔文本作者不考虑边缘情况。

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

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

更新:使用 Papa Parse 4,相同的文件在 Firefox 中只用了大约 30 秒。Papa Parse 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 可以使用网络工作者来保持您的网站反应。

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

我正在使用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-request 已弃用。 你可以使用d3-fetch

这是一个解析 CSV 数据的 JavaScript 函数,其中包含引号内的逗号。

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

是此代码的工作小提琴

享受! ——柯伦

您可以使用 PapaParse 来提供帮助。 https://www.papaparse.com/

这是一个 CodePen。 https://codepen.io/sandro-wiggers/pen/VxrxNJ

Papa.parse(e, {
            header:true,
            before: function(file, inputElem){ console.log('Attempting to Parse...')},
            error: function(err, file, inputElem, reason){ console.log(err); },
            complete: function(results, file){ $.PAYLOAD = results; }
        });

如果您想在不使用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>

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 引擎上的第一个替代方案之前执行,并将引号视为未引用值的一部分。 我不会问 - 只是让它工作。

根据接受的答案

我通过在此处将 1 更改为 0 来实现此功能:

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

变成

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

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

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

                        }
                      }
                    }

实际上,您可以使用一个名为any-text的轻量级库。

  • 安装依赖项
npm i -D any-text
  • 使用自定义命令读取文件
var reader = require('any-text');
 
reader.getText(`path-to-file`).then(function (data) {
  console.log(data);
});

或使用 async-await :

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

这是另一种将外部 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]);
    }
})

希望这对将来的人有所帮助!

有点晚了,但我希望它可以帮助某人。

前段时间,我什至遇到了一个问题,即字符串数据在两者之间包含\n ,而在读取它用来读取不同行的文件时。

例如。

"Harry\nPotter","21","Gryffindor"

在读的时候:

Harry
Potter,21,Gryffindor

我在我的角度项目中使用了一个库csvtojson来解决这个问题。

您可以使用以下代码将 CSV 文件作为字符串读取,然后将该字符串传递给 csvtojson 库,它将为您提供 JSON 列表。

示例代码:

const csv = require('csvtojson');
if (files && files.length > 0) {
    const file: File = files.item(0);
    const reader: FileReader = new FileReader();
    reader.readAsText(file);
    reader.onload = (e) => {
    const csvs: string = reader.result as string;
    csv({
        output: "json",
        noheader: false
    }).fromString(csvs)
        .preFileLine((fileLine, idx) => {
        //Convert csv header row to lowercase before parse csv file to json
        if (idx === 0) { return fileLine.toLowerCase() }
        return fileLine;
        })
        .then((result) => {
        // list of json in result
        });
    }
}

我使用jquery-csv来做到这一点。

evanplaice/jquery-csv

我提供了两个例子如下

 async function ReadFile(file) { return await file.text() } function removeExtraSpace(stringData) { stringData = stringData.replace(/,( *)/gm, ",") // remove extra space stringData = stringData.replace(/^ *| *$/gm, "") // remove space on the beginning and end. return stringData } function simpleTest() { let data = `Name, Age, msg foo, 25, hello world bar, 18, "!! 🐬 !!" ` data = removeExtraSpace(data) console.log(data) const options = { separator: ",", // default "," . (You may want to Tab "\t" or somethings. delimiter: '"', // default " headers: true // default true } // const myObj = $.csv.toObjects(data, options) const myObj = $.csv.toObjects(data) // If you want to use default options, then you can omit them. console.log(myObj) } window.onload = () => { const inputFile = document.getElementById("uploadFile") inputFile.onchange = () => { const inputValue = inputFile.value if (inputValue === "") { return } const selectedFile = document.getElementById('uploadFile').files[0] const promise = new Promise(resolve => { const fileContent = ReadFile(selectedFile) resolve(fileContent) }) promise.then(fileContent => { // Use promise to wait for the file reading to finish. console.log(fileContent) fileContent = removeExtraSpace(fileContent) const myObj = $.csv.toObjects(fileContent) console.log(myObj) }) } }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-csv/1.0.11/jquery.csv.min.js"></script> <label for="uploadFile">Demo 1</label> <input type="file" id="uploadFile" accept=".csv"/> <button onclick="simpleTest()">Demo 2</button>

使用此函数csvToObjs ,您可以数据条目从CSV 格式转换为对象数组

 function csvToObjs(string) { const lines = data.split(/\r\n|\n/); let [headings, ...entries] = lines; headings = headings.split(','); const objs = []; entries.map(entry=>{ obj = entry.split(','); objs.push(Object.fromEntries(headings.map((head, i)=>[head, obj[i]]))); }) return objs; } data = `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` console.log(csvToObjs(data));

这是一个老问题,在 2022 年有很多方法可以实现这一目标。 首先,我认为D3是数据处理的最佳替代方案之一。 它是开源的并且可以免费使用,但它也是模块化的,所以我们可以只导入fetch 模块

这是一个基本的例子。 我们将使用传统模式,因此我将导入整个D3库。 现在,让我们调用d3.csv function 就完成了。 这个function内部调用了fetch方法,因此可以打开dataURL、url、文件、blob等。

 const fileInput = document.getElementById('csv') const outElement = document.getElementById('out') const previewCSVData = async dataurl => { const d = await d3.csv(dataurl) console.log({ d }) outElement.textContent = d.columns } const readFile = e => { const file = fileInput.files[0] const reader = new FileReader() reader.onload = () => { const dataUrl = reader.result; previewCSVData(dataUrl) } reader.readAsDataURL(file) } fileInput.onchange = readFile
 <script type="text/javascript" src="https://unpkg.com/d3@7.6.1/dist/d3.min.js"></script> <div> <p>Select local CSV File:</p> <input id="csv" type="file" accept=".csv"> </div> <pre id="out"><p>File headers will appear here</p></pre>

如果我们不想使用任何库,而只想使用 pain JavaScrip (Vanilla JS),并且我们设法将文件的文本内容作为data ,并且不想使用d3 ,我们可以实现一个简单的 function这会将data拆分为text数组,然后我们将提取第一行并拆分为headers数组, text的 rest 将是我们将处理的lines 之后,我们 map 每一line并提取其values ,并从一个数组中创建row object,该数组是通过将每个header映射到values[index]中的对应值而创建的。

笔记:

我们还要使用一个小技巧array对象在 JavaScript 也可以有属性。 是的,所以我们将定义一个属性rows.headers并将headers分配给它。

 const data = `heading_1,heading_2,heading_3,heading_4,heading_5 value_1_1,value_2_1,value_3_1,value_4_1,value_5_1 value_1_2,value_2_2,value_3_2,value_4_2,value_5_2 value_1_3,value_2_3,value_3_3,value_4_3,value_5_3` const csvParser = data => { const text = data.split(/\r\n|\n/) const [first, ...lines] = text const headers = first.split(',') const rows = [] rows.headers = headers lines.map(line => { const values = line.split(',') const row = Object.fromEntries(headers.map((header, i) => [header, values[i]])) rows.push(row) }) return rows } const d = csvParser(data) // Accessing to the theaders attribute const headers = d.headers console.log({headers}) console.log({d})

最后,让我们使用 fetch 和解析 csv 文件来实现一个普通的 JS 文件加载器。

 const fetchFile = async dataURL => { return await fetch(dataURL).then(response => response.text()) } const csvParser = data => { const text = data.split(/\r\n|\n/) const [first, ...lines] = text const headers = first.split(',') const rows = [] rows.headers = headers lines.map(line => { const values = line.split(',') const row = Object.fromEntries(headers.map((header, i) => [header, values[i]])) rows.push(row) }) return rows } const fileInput = document.getElementById('csv') const outElement = document.getElementById('out') const previewCSVData = async dataURL => { const data = await fetchFile(dataURL) const d = csvParser(data) console.log({ d }) outElement.textContent = d.headers } const readFile = e => { const file = fileInput.files[0] const reader = new FileReader() reader.onload = () => { const dataURL = reader.result; previewCSVData(dataURL) } reader.readAsDataURL(file) } fileInput.onchange = readFile
 <script type="text/javascript" src="https://unpkg.com/d3@7.6.1/dist/d3.min.js"></script> <div> <p>Select local CSV File:</p> <input id="csv" type="file" accept=".csv"> </div> <pre id="out"><p>File contents will appear here</p></pre>

我用这个文件来测试它

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM