Как считать файл csv c

Обновлено: 04.07.2024

Разбор файла Comma Separated Value (CSV) поначалу кажется достаточно простым. Однако эта задача весьма быстро становится все более сложной по мере того, как проясняются болевые точки CSV-файлов. Если вы не знакомы с этим форматом, то CSV-файлы хранят данные в виде чистого текста. Каждая строка в файле образует запись. В каждой записи есть поля, обычно отделяемые запятыми, отсюда и произошло название формата — значения, разделенные запятыми.

Сегодня разработчики используют стандартные форматы для обмена данными. Формат CSV восходит к ранним временам программной индустрии еще до появления JSON и XML. Хотя существует документ RFC (Request for Comments) для CSV-файлов (bit.ly/1NsQlvw), он не имеет официального статуса. Кроме того, он был создан в 2005 году, десятилетия спустя после того, как CSV-файлы начали появляться еще в 1970-х. В итоге существует довольно много вариаций CSV-файлов, и правила не совсем внятны. Например, поля CSV-файла могут разделяться табуляторами, точками с запятой или любым символом.

На практике стандартом де-факто стала Excel-реализация импорта и экспорта CSV, и именно она чаще всего встречается в индустрии — даже за пределами экосистемы Microsoft. Соответственно предположения, которые я допускаю в этой статье о «корректном» разборе и форматировании, будут базироваться на том, как Excel импортирует/экспортирует CSV-файлы. Большинство CSV-файлов отвечают реализации в Excel, тем не менее, таковыми являются не все файлы. В связи с этим я предложу стратегию для обработки такой неопределенности.

Возникает вопрос по существу: «Зачем писать средство разбора очень старого псевдоформата на самой новой платформе?». Ответ прост: во многих организациях имеются устаревшие системы, работающие с данными. Благодаря долгому существованию этого файлового формата почти все эти системы умеют экспортировать в CSV. Более того, экспорт данных в CSV требует минимума времени и усилий. А значит, существует множество CSV-файлов в наборах корпоративных и правительственных данных.

Проектирование средства разбора CSV универсального назначения

Несмотря на отсутствие официального стандарта CSV-файлы, как правило, имеют общие черты.

Вообще говоря, CSV-файлы являются чистым текстом, содержат по одной записи на строку, записи в каждой строке отделяются разделителем, имеют разделитель из одного символа и представляют поля в одинаковом порядке.

Эти общие черты обрисовывают универсальный алгоритм, который работал бы в три этапа.

  1. Разбиваем файл на строки по разделителю строк.
  2. Разбиваем каждую строку по разделителю полей.
  3. Присваиваем значение каждого поля какой-то переменной.

Это можно было бы реализовать сравнительно легко. Код на рис. 1 разбирает входную строку CSV в List<Dictionary<string, string>>.

Рис. 1. Разбор входной строки CSV в List<Dictionary<string,string>>

Этот подход отлично работает на примере следующего списка офисов, числа сотрудников и объемов продаж:

Чтобы получить значения из строки (string), вы должны были бы перебирать List и извлекать значения в Dictionary, используя индексацию полей от нуля. Например, получение поля офиса выглядело бы так:

Хотя это работает, код не столь читаем, каким мог бы быть.

Более эффективный словарь

Многие CSV-файлы включают строку заголовка (header row) для имени поля. Разработчикам было бы легче использовать средство разбора, если бы оно использовало имя поля в качестве ключа для словаря. Поскольку в конкретном CSV-файле может не оказаться строки заголовка, следует добавить свойство, сообщающее о наличии этой информации:

Например, образец CSV-файл со строкой заголовка мог бы выглядеть так:

В идеале, средство разбора CSV должно быть способно задействовать преимущества этой части метаданных. Это сделало бы код более читаемым. Получение поля Office Division выглядело бы следующим образом:

Пустые поля

Пустые поля часто встречаются в наборах данных. В CSV-файлах поле без информации представлено пустым полем в записи. При этом наличие разделителя все равно обязательно. Скажем, если для офиса East нет данных Employee, запись принимает такой вид:

Если же нет данных Unit Sales, а также данных Employee, запись выглядит так:

У каждой организации свои стандарты качества данных. Некоторые могут помещать в пустое поле значение по умолчанию, чтобы сделать CSV-файл более понятным человеку. Значения по умолчанию для чисел — это обычно 0 или NULL, а для строк — "" или NULL.

Сохранение гибкости

Учитывая всю неоднозначность файлового формата CSV, код не может делать никаких допущений. Нет никаких гарантий, что разделитель полей будет запятой, а разделитель записей — новой строкой.

Соответственно оба они будут свойствами класса CSVParser:

Чтобы упростить разработчикам использование этого компонента, нужно задать параметры по умолчанию, которые будут применяться в большинстве случаев:

Если кто-то пожелает изменить разделитель по умолчанию на табулятор, то необходимый код весьма прост:

Экранированные символы

Что будет, если само поле содержит символ-разделитель, например запятую? А если вместо объемов продаж по регионам данные содержат информацию о городе и штате? Как правило, в CSV-файлах эту проблему обходят, заключая все поле в кавычки наподобие:

Этот алгоритм превратил бы одно значение поля “New York, NY” в два отдельных поля со значениями, разбитыми по запятой: “New York” и “NY”.

В этом случае разделение названий города и штата может не оказаться не столь важным, но данные по-прежнему загрязняются дополнительными символами-кавычками. Хотя здесь их достаточно легко удалить, выполнить очистку более сложных данных может быть не так просто.

Теперь усложним задачу

Метод экранирования запятых внутри полей вводит необходимость в экранировании другого символа: кавычек. Что будет, если, например, в исходных данных были кавычки, как показано в табл. 1?

Табл. 1. Исходные данные с кавычками

Office Division Employees Unit Sales Office Motto
New York, NY 73 8300 “We sell great products”
Richmond, VA 42 3000 “Try it and you'll want to buy it”
San Jose, CA 35 4250 “Powering Silicon Valley!”
Chicago, IL 18 1200 “Great products at great value”

Исходный текст в самом CSV-файле выглядел бы так:

Один символ кавычек (“) после экранирования превращается в три символа кавычек (“””), что добавляет алгоритму интересную особенность. Конечно, сразу же возникает резонный вопрос: почему одна кавычка превращается в три? Как и в поле Office Division, содержимое этого поля заключается в кавычки. Чтобы экранировать символы кавычек, которые являются частью контента, они удваиваются. Поэтому “ становится “”.

Другой пример (табл. 2) более наглядно продемонстрирует этот процесс.

Табл. 2. Данные цитат

Quote
"The only thing we have to fear is fear itself." -President Roosevelt
"Logic will get you from A to B. Imagination will take you everywhere." -Albert Einstein

Данные из табл. 2 были бы представлены в CSV следующим образом:

Теперь должно быть понятнее, что поле заключается в кавычки и что индивидуальные кавычки в содержимом поля удваиваются.

Пограничные случаи

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

Инверсия управления спешит на помощь

Учитывая размытость стандарта CSV, не практично писать универсальное средство разбора для всех случаев. Гораздо разумнее писать средство разбора, подходящее для конкретных потребностей какого-либо приложения. Используя инверсию управления (Inversion of Control), вы можете адаптировать механизм разбора под конкретные требования.

С этой целью я создам интерфейс, определяющий две базовые функции синтаксического разбора: для получения записей и извлечения полей. Я решил сделать интерфейс IParserEngine асинхронным. Это гарантирует, что любое приложение, использующее этот компонент, не перестанет отвечать при разборе CSV-файла даже очень большого размера:

После этого я добавляю в класс CSVParser следующее свойство:

И предлагаю разработчикам выбор: использовать средство разбора по умолчанию или встроить собственное. Чтобы упростить эту задачу, я перегрузил конструктор:

Теперь класс CSVParser предоставляет базовую инфраструктуру, а реальная логика синтаксического анализа содержится в интерфейсе IParserEngine. Для удобства разработчиков я создал DefaultParserEngine, который может обрабатывать большинство CSV-файлов.

Задача для читателя

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

Уверен, что на практике вы встретите CSV-файлы, которые DefaultParserEngine не сумеет обработать. И здесь очень хорошо подходит шаблон встраивания зависимостей. Если разработчику нужно средство разбора, которое может обрабатывать пограничные случаи, или требуется написать нечто более производительное, это определенно приветствуется. Механизмы разбора можно заменять без изменений в коде-потребителе.

Заключение

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

Будь на то выбор, большинство разработчиков, по-видимому, исключило бы CSV-файлы из своих решений. Однако их широкая распространенность в устаревших корпоративных и правительственных наборах данных препятствует этому в большинстве случаев.

Исходный код можно скачать по ссылке bit.ly/1To1IVI.

Выражаю благодарность за рецензирование статьи эксперту Рэчел Аппель (Rachel Appel).

В этой статье о Python вы узнаете как работать с дробями.

В этой статье по программированию на C++ (также известном как CPP) я покажу вам, как прочитать и обработать файл CSV (значения, разделенные запятыми). Без использования внешних библиотек.

Для этого нам нужно прочитать файл построчно, а затем разбить каждую строку в соответствии с разделителем. Все это мы будем делать с помощью C++ и встроенных функций.

Алгоритм

Давайте сначала проанализируем, что нам нужно сделать. Мы будем читать CSV с помощью C++, поэтому сначала нам нужно открыть файл и прочитать его построчно, поскольку в каждой строке содержится новый набор значений.

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

В этом цикле мы будем разбивать строку (линию) в соответствии с разделителем, которым в данном случае является запятая. После чего мы можем извлечь каждое значение в отдельную переменную и сделать с ним все, что угодно, например, распечатать или записать в другой файл.

CSV файл

Для этого примера я буду использовать CSV, который выглядит следующим образом:


Как видите, у нас есть 4 строки и в каждой из них 7 столбцов.

Важно, чтобы CSV имел определенную и последовательную структуру.

Примечание: мы собираемся прочитать файл и рассматривать все данные как строку. Затем вы можете преобразовать их в double, int и так далее.

Чтение CSV с помощью C++

Теперь давайте посмотрим на код. Сначала мы открываем файл и читаем его:

Внутри цикла у нас появится строка. Пришло время разделить ее для хранения ее значений. Как сказано выше, разделителем является запятая. Далее мы делаем следующее:

Как вы можете видеть, извлечение значений происходит со строки 4 по строку 10, мы читаем из строчки и помещаем каждое значение внутрь каждой переменной. Помните, что они должны располагаться в том же порядке, что и столбцы в CSV-файле.

Полный код выглядит следующим образом:

Вот как использовать C++ для чтения CSV.

Сохраните статью в социальных сетях, чтобы не потерять.

Похожие записи

В стандартной библиотеке у нас есть модуль для чтения файлов csv. Этот модуль не очень…

Kubernetes становится все более популярным средством развертывания приложений, особенно в архитектурах микросервисов. С другой стороны,…

В этой статье о Python мы рассмотрим, как получить наименьшее общее кратное (НОК) двух чисел.…

Мне нужно загрузить и использовать данные CSV-файла на C++. На данный момент это может быть просто парсер с разделителями-запятыми (т. е. не беспокойтесь о выходе из новых строк и запятых). Основная потребность-это построчный синтаксический анализатор, который будет возвращать вектор для следующей строки при каждом вызове метода.

Я никогда не использовал Boost Дух, но я готов попробовать. Но только если нет более простого решения, которое я упускаю из виду.

Если вы не заботитесь о побеге запятой и новой строки,
И вы не можете вставлять запятую и новую строку в кавычки (если вы не можете избежать этого. )
тогда его только около трех строк кода (OK 14 ->, но его только 15, чтобы прочитать весь файл).

Я бы просто создать класс, представляющий строку.
Затем поток в этот объект:

но с небольшой работой мы могли бы технически создать итератор:

решение с помощью Boost Tokenizer:

на Библиотека Инструментария Строк C++ (StrTk) имеет класс сетки токенов, который позволяет загружать данные либо из текстовые файлы, строки или char буферов, и анализировать / обрабатывать их в виде строки-столбца.

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

больше примеров можно найти здесь

моя версия не использует ничего, кроме стандартной библиотеки C++11. Он хорошо справляется с цитатой Excel CSV:

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

вы можете использовать Boost Tokenizer с escaped_list_separator.

escaped_list_separator анализирует надмножество csv. Boost:: tokenizer

Это использует только файлы заголовков Boost tokenizer, никаких ссылок на библиотеки boost не требуется.

использование Spirit для разбора CSV не является излишним. Spirit хорошо подходит для микро-разбора задач. Например, с Spirit 2.1 это так же просто, как:

вектор v заполняется значениями. существует ряд учебных пособий касаясь этого в новых документах Spirit 2.1, которые только что были выпущены с Boost 1.41.

учебник прогрессирует от простого к сложному. Парсеры CSV представлены где-то посередине и касаются различные техники использования Духа. Сгенерированный код такой же жесткий, как рукописный. Проверьте ассемблер автоматически!

Если вы DO позаботьтесь о правильном разборе CSV, это сделает это. относительно медленно, поскольку он работает по одному char за раз.

при использовании Boost Tokenizer escaped_list_separator для CSV-файлов следует знать следующее:

  1. требуется escape-символ (по умолчанию back-slash - \)
  2. для этого требуется символ разделителя / разделителя (запятая по умолчанию)
  3. для этого требуется символ цитаты (цитата по умолчанию - ")

формат CSV, указанный wiki, утверждает, что поля данных могут содержать разделители в кавычках (поддерживается):

1997, Ford, E350, "супер, роскошный грузовик"

формат CSV, указанный wiki, гласит, что одинарные кавычки должны обрабатываться двойными кавычками (escaped_list_separator удалит все символы кавычек):

1997, Ford, E350, "супер ""роскошный ""грузовик"

формат CSV не указывает, что любые символы обратной косой черты должны быть удалены (escaped_list_separator удалит все escape письмена.)

  1. сначала замените все символы обратной косой черты ( \ ) двумя символами обратной косой черты ( \ \ ), чтобы они не были удалены.
  2. во-вторых, замените все двойные кавычки ( "" ) одним символом обратной косой черты и кавычкой (\")

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

не очень, но это работает, пока в кавычках нет новых строк.

вы можете посмотреть на мой проект FOSS CSVfix (обновили ссылку), который является редактором потока CSV, написанным на C++. Парсер CSV не является призом, но выполняет работу, и весь пакет может делать то, что вам нужно, без написания кода.

посмотреть alib/src / a_csv.cpp для парсера CSV и csvlib/src / csved_ioman.cpp ( IOManager::ReadCSV ) пример использования.

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

в качестве примера того, как я хотел бы использовать входной поток CSV, рассмотрим следующий ввод (взятый из страница Википедии на CSV):

затем я хотел иметь возможность читать в данных, как это:

Это было решение, которое я получил.

со следующими помощниками, которые могут быть упрощены новыми шаблонами интегральных признаков в C++11:

другую библиотеку ввода-вывода CSV можно найти здесь:

другое решение, аналогичное ответ Локи Астари в C++11. Строки здесь std::tuple s данного типа. Код сканирует одну строку, затем сканирует до каждого разделителя, а затем преобразует и сбрасывает значение непосредственно в кортеж (с небольшим количеством кода шаблона).

Advanges:

  • довольно чистый и простой в использовании, только в C++11.
  • автоматическое преобразование типов в std::tuple<t1, . > через operator>> .

чего не хватает:

  • побег и цитируешь
  • нет обработки ошибок в случае искаженного CSV.

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

вот еще одна реализация синтаксического анализатора CSV Unicode (работает с wchar_t). Я написал часть, а Джонатан Леффлер-остальное.

Примечание: этот парсер предназначен для репликации поведения Excel как можно ближе, особенно при импорте сломанный или деформированный CSV-файлов.

Это код как SSCCE (Короткий, Самодостаточный, Правильный Пример).

первое, что вам нужно сделать, это убедиться, что файл существует. Выполнять это вам просто нужно попробовать и открыть поток файлов по пути. После вас открыли файловый поток use stream.fail (), чтобы увидеть, работает ли он так, как ожидалось, или нет.

вы также должны убедиться, что предоставленный файл является правильным типом файла. Для этого вам нужно посмотреть путь к файлу, пока вы найдете расширение файла. Как только у вас будет расширение файла, убедитесь что Это.CSV-файл.

эта функция фактически вызовет проверки ошибок, созданные выше, а затем проанализирует файл.

Я написал только заголовок, C++11 CSV parser. Он хорошо протестирован, быстрый, поддерживает всю спецификацию CSV (поля кавычек, разделитель/Терминатор в кавычках, экранирование цитат и т. д.), и настраивается для учета CSV, которые не соответствуют спецификации.

конфигурация сделана через Свободный интерфейс:

парсинг-это просто диапазон, основанный на цикле:

Извините, но все это кажется очень сложным синтаксисом, чтобы скрыть несколько строк кода.

почему бы и нет:

вот код для чтения матрицы, обратите внимание, что у вас также есть функция csvwrite в matlab

Вы можете открыть и прочитать .csv-файл с использованием функций fopen, fscanf, но важно проанализировать данные.Самый простой способ проанализировать данные с помощью разделителя.На всякий случай .csv, разделитель','.

предположим, что ваш data1.CSV-файл выглядит следующим образом :

вы можете токенизировать данные и хранить в массиве char, а затем использовать функцию atoi() etc для соответствующих преобразований

[^,], ^ -Он инвертирует логику, означает соответствие любой строке, которая не содержит запятую, затем последний, говорит, чтобы соответствовать запятая, которая завершила предыдущую строку.

вы должны гордиться, когда вы используете что-то настолько красивое, как boost::spirit

вот моя попытка парсера (почти), соответствующего спецификациям CSV по этой ссылке CSV в спецификации (мне не нужны разрывы строк в полях. Также удаляются пробелы вокруг запятых).

после того, как вы преодолеете шокирующий опыт ожидания 10 секунд для компиляции этого кода :), Вы можете сесть и наслаждаться.

тест (пример украден из Википедия):

это решение обнаруживает эти 4 случая

полный класс составляет

Он читает файл посимвольно, и читает 1 строку в вектор (строк), поэтому подходит для очень больших файлов.

итерировать до пустой строки возвращается (конец файла). Подряд-это вектор, где каждая запись-это CSV колонна.

вы также можете взглянуть на возможности Qt библиотека.

Он имеет поддержку регулярных выражений, А класс QString имеет хорошие методы, например split() возврат QStringList, списка строк, полученных путем разделения исходной строки с предоставленным разделителем. Должно хватить для CSV-файла..

чтобы получить столбец с именем заголовка я использую следующие: C++ наследование Qt проблема qstring

Если вы не хотите иметь дело с включением boost в свой проект (он значительно больше, если все, что вы собираетесь использовать его для CSV-анализа. )

Мне повезло с разбором CSV здесь:

он обрабатывает поля с кавычками, но не обрабатывает встроенные символы \n (что, вероятно, хорошо для большинства применений).

Это старый поток, но он все еще находится в верхней части результатов поиска, поэтому я добавляю свое решение с помощью std::stringstream и простого метода замены строки Yves Baumes, который я нашел здесь.

в следующем примере будет читать файл строка за строкой, игнорировать строки комментариев, начинающиеся с//, и анализировать другие строки в комбинации строк, ints и Double. Stringstream выполняет синтаксический анализ, но ожидает, что поля будут разделены пробелами, поэтому я использую stringreplace для преобразования запятых в пространства в первую очередь. Он обрабатывает вкладки ок, но не имеет дело с кавычками.

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

для чего это стоит, вот моя реализация. Он имеет дело с вводом wstring, но может быть легко настроен на строку. Он не обрабатывает новую строку в полях (как и мое приложение, но добавление его поддержки не слишком сложно), и он не соответствует концу строки "\r\n" в соответствии с RFC (при условии, что вы используете std::getline), но он правильно обрабатывает обрезку пробелов и двойные кавычки (надеюсь).

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

Многие программные продукты, которые имеют дело с числами и вычислениями, имеют возможность выводить данные в файл с разделением запятыми (CSV). Этот формат может быть эффективным способом передачи данных между различными программами, так как он удобочитаем и довольно прост в обращении. Многим программам на Си, которые имеют дело с данными, скорее всего, в какой-то момент придется читать из файла CSV.


Программы табулирования и расчета могут выводить данные в формате CSV

Шаг 1

Шаг 2

Шаг 3

Создайте метод в вашей программе, который будет обрабатывать чтение файла CSV. Это должно быть доступно для остальной части вашей программы и, вероятно, должно работать с общими структурами данных, чтобы другие методы могли получить доступ к данным, которые были прочитаны. Передайте параметр по ссылке, чтобы устранить необходимость в возвращаемом значении , Пример прототипа функции: void ParseCSV (char * filename, data & input);

Шаг 4

Шаг 5

Шаг 6

Создайте объект файла, который будет читать данные, используя следующий код: FILE * pInput;

Шаг 7

char buf BUFFER_SIZE;

Шаг 8

Откройте файл со следующим кодом и назначьте его ранее созданному объекту FILE: pInput = fopen ("filename", "r")

Шаг 9

Прочитайте в строке файла, используя следующий код:

fgets (buf, sizeof (buf), pInput)

Шаг 10

Разбираем CSV с помощью функции "strtok". Создайте новую строку символов, чтобы указать на токены, и инициализируйте ее данными из строки, прочитанной выше: char * tok = strtok (buf, ",")

Шаг 11

Шаг 12

Шаг 13

Как я могу прочитать файл VCF?

Как я могу прочитать файл VCF?

Используйте файлы VCard для импорта или экспорта контактов из адресных книг различных программ, таких как Outlook, Gmail или Windows Live Mail. VCF файлы могут содержать много частей .

Как я могу прочитать файл DMP?

Как я могу прочитать файл DMP?

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

Как конвертировать файл PST в файл CSV

Как конвертировать файл PST в файл CSV

Outlook, впервые выпущенный в 1997 году, является одним из наиболее широко используемых в мире приложений для управления личной информацией. Включено в комплект производительности Microsoft Office .

Читайте также: