Как читать данные из файла * .CSV, используя JavaScript?

196

Мои данные CSV выглядит так:

Заголовок1, Заголовок 2, heading3, heading4, heading5, value1_1, value2_1, value3_1, value4_1, value5_1, value1_2, value2_2, value3_2, value4_2, value5_2 ....

Как вы читаете эти данные и конвертируете в массив, подобный этому, используя Javascript ?:

[заголовок1: значение1_1, заголовок2: значение2_1, заголовок3: значение3_1, заголовок4: значение4_1, заголовок5: значение5_1], [заголовок1: значение1_2, заголовок2: значение2_2, заголовок3: значение3_2, заголовок4: значение4_2, заголовок 5: значение5_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
Да, я заранее знаю, что здесь ровно пять полей.
Махеш Тумар
1
Следующий вопрос: разрешен ли jQuery в решении? Вы использовали тег, но ваш пример кода - чистый JavaScript.
Blazemonger
да, jQuery разрешен, поэтому я включаю его в тег.
Махеш Тумар
1
Я не думаю, что использование file://...разрешено XMLHttpRequest.
Ноэль Льеварес

Ответы:

118

ПРИМЕЧАНИЕ. Я придумал это решение, прежде чем мне напомнили обо всех «особых случаях», которые могут возникнуть в действительном файле CSV, например, экранированные кавычки. Я оставляю свой ответ тем, кто хочет чего-то быстрого и грязного, но я рекомендую ответ Эвана для точности.


Этот код будет работать, когда ваш 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/

Blazemonger
источник
4
Кстати, это предполагает, что файл CSV на самом деле имеет несколько строк - это то, что allText.split(/\r\n|\n/)разделяет. Если все ваши данные на самом деле представляют собой одну длинную строку данных, разделенных запятыми, без перевода строки, это не настоящий файл CSV.
Blazemonger
1
Привет, я использую этот код: но нет вывода. Просто пустое предупреждение отображается. мой файл выглядит так: заголовок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 Оба файла csv.html и data.txt находятся в одной папке
Mahesh
Если это неправильный файл (или данные), то как должен выглядеть мой файл?
Махеш Тумар
7
Код может не обрабатывать все допустимые стандартные CSV-файлы IETF и может завершиться ошибкой, если есть строки со встроенными запятыми, переносами строк или двойными кавычками. Например, 1, "IETF allows ""quotes"", commas and \nline breaks"это разрешено, поскольку строка окружена двойными кавычками, а двойные кавычки экранированы.
прототип
1
Я пытался прочитать файл .csv с Mac. Мне удалось заставить этот скрипт распознавать символы новой строки только после того, как я изменил первый сплит на этот. var allTextLines = allText.split("\r"); После этого он работал отлично! Спасибо!
Джо
207

Не нужно писать свой собственный ...

В библиотеке jQuery-CSV есть функция, $.csv.toObjects(csv)которая выполняет сопоставление автоматически.

Примечание. Библиотека предназначена для обработки любых данных CSV, совместимых с RFC 4180 , включая все неприятные крайние случаи, которые игнорируются большинством «простых» решений.

Как уже говорилось в @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):

Вывод, сохраненный в «data», будет:

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

Обновить:

Отредактировано для использования набора данных, предоставленного операцией, и содержит ссылку на демонстрацию, где данные могут быть проверены на достоверность.

Update2:

Из-за закрытия Google Code. jquery-CSV переехал на GitHub

Эван Плейс
источник
3
IOW, «toObject» это или можно думать как «toJSON», нет? И является ли двоеточие после вызова toObjects (csv) опечаткой? IOW, это не точка с запятой?
Б. Клэй Шеннон
11
CSV - это имя файла?
пузырь
10
Фантастическая библиотека. К сведению, csvпереданный параметр является строкой csv - считайте файл csv как текст, чтобы получить строку csv.
callmekatootie
3
@Evan Plaice Как использовать эту библиотеку для чтения из файла CSV?
Рича Синха
1
@RichaSinha Чтение файла в виде текстового буфера с помощью API-файла HTML5 или AJAX. Затем передайте строковый буфер в парсер. В результате получится массив данных. Смотрите страницу проекта для примеров.
Эван Плейс,
75

Не разделяйте запятыми - это не сработает для большинства файлов CSV, и у этого вопроса слишком много представлений, чтобы входные данные типа asker можно было применить ко всем. Парсинг CSV довольно страшен, так как нет действительно официального стандарта, и многие авторы текста с разделителями не рассматривают крайние случаи.

Этот вопрос старый, но я считаю, что теперь есть лучшее решение, когда доступен Papa Parse . Это библиотека, которую я написал с помощью авторов, которая анализирует текст или файлы CSV. Это единственная из известных мне JS-библиотек, которая поддерживает файлы размером в гигабайты. Он также корректно обрабатывает некорректный ввод.

1 ГБ файл анализируется за 1 минуту: Разобрали 1 ГБ файл за 1 минуту

( Обновление: в Papa Parse 4 этот же файл занимал всего около 30 секунд в Firefox. 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 может использовать веб-работников, чтобы ваш веб-сайт реагировал.

Папа может автоматически определять разделители и сопоставлять значения со столбцами заголовка, если имеется строка заголовка. Он также может превращать числовые значения в действительные типы чисел. Он соответствующим образом анализирует разрывы строк, кавычки и другие странные ситуации и даже обрабатывает некорректно введенные данные настолько надежно, насколько это возможно. Я черпал вдохновение из существующих библиотек для создания папы, поэтому поддерживаю другие реализации JS.

Matt
источник
Папа прост в использовании и быстро! Спасибо!
Технотроник
+1 Хорошая работа на Papa Parse. Я хотел бы изучить это подробно когда-нибудь, чтобы увидеть, как вы обрабатываете большие файлы и потоковую передачу. Я очень рад, что другие разработчики пишут полнофункциональные парсеры, которые начинают с того места, где остановился jquery-csv.
Эван Плейс
3
@EvanPlaice Спасибо. Вам может понравиться эта презентация, которую я дал вчера вечером на местном собрании
Мэтт
1
@ Мэтт Это была потрясающая презентация, в которой рассказывается о разборе папы более понятным способом
Шива
1
@ Malky.Kid Это недопустимый CSV (то есть пробелы в неразграниченном значении не годятся). Реализация формата CSV в MS Excel - отстой. Если у вас все еще есть доступ к исходному файлу, должна быть возможность включить разделители кавычек. Как только вы это сделаете, ваши данные должны работать с любым парсером CSV.
Эван Плейс
10

Я использую d3.js для анализа файла CSV. Очень прост в использовании. Вот документы .

шаги:

  • npm установить d3-запрос

Используя Es6;

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

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

Пожалуйста, смотрите документы для более.

Обновление - d3-запрос устарел. вы можете использовать d3-fetch

Бимал Грг
источник
4

Вы можете использовать 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; }
        });
Сандро Виггерс
источник
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));

Вот как вы можете преобразовать данные в объекты, такие как csv-парсер D3 (который является надежным сторонним решением):

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

Надеюсь, это поможет кому-то в будущем!

FredFury
источник
Привет из будущего, поэтому я попробовал этот ответ, и )в строке 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 и рассматривал кавычки как часть значения без кавычек. Я не буду просить - просто заставил это работать.

Жерар ОНЕЙЛ
источник
К сожалению, я попал в бесконечный цикл с этой функцией.
Хауке
@ Хаук - если бы вы могли разбить данные на пару столбцов и строк, которые все еще производят бесконечный цикл, я был бы признателен - это может дать мне понимание того, почему я терпел неудачу раньше.
Джерард
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]);

                        }
                      }
                    }
рахул кулкарни
источник
Хотя этот код может решить вопрос, том числе объяснение того, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, получит больше голосов "за". Помните, что вы отвечаете на вопрос для читателей в будущем, а не только для того, кто спрашивает сейчас. Пожалуйста, отредактируйте свой ответ, чтобы добавить объяснения и указать, какие ограничения и предположения применяются. Из обзора
двойной сигнал
0

На самом деле вы можете использовать легковесную библиотеку под названием 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');
  });
});
Абхинаба
источник