CSV-анализ в Java - рабочий пример..?

Я хочу написать программу для проекта Java Java для анализа некоторых CSV, которые я не знаю. Я знаю тип данных для каждого столбца, хотя я не знаю разделителя.

Проблема, которую я даже не знаю, как исправить, - это проанализировать Date или даже DateTime Columns. Они могут быть в одном из многих форматов.

Я нашел много библиотек, но не знаю, что лучше для моих нужд: http://opencsv.sourceforge.net/ http://www.csvreader.com/java_csv.php http://supercsv.sourceforge.net/ http://flatpack.sourceforge.net/

Проблема в том, что я являюсь новичком java. Я боюсь, что не те библиотеки могут делать то, что мне нужно, или я не могу убедить их сделать это.

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

  • автоматически расщепляется в столбцах (ограничитель неизвестен, известны типы столбцов)
  • отбрасывается в Columntype (должен справляться с $,% и т.д.)
  • конвертировать даты в объекты Java Date или Calendar

Было бы неплохо получить как можно больше примеров кода по электронной почте.

Спасибо большое! AS

Ответы

Ответ 1

У вас также есть библиотека Apache Commons CSV, возможно, она делает то, что вам нужно. См. руководство. Обновлено до версии 1.1 в 2014-11.

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

Ответ 2

Существует серьезная проблема с использованием

String[] strArr=line.split(",");

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

Существует очень простой способ проанализировать это:

/**
* returns a row of values as a list
* returns null if you are past the end of the input stream
*/
public static List<String> parseLine(Reader r) throws Exception {
    int ch = r.read();
    while (ch == '\r') {
        //ignore linefeed chars wherever, particularly just before end of file
        ch = r.read();
    }
    if (ch<0) {
        return null;
    }
    Vector<String> store = new Vector<String>();
    StringBuffer curVal = new StringBuffer();
    boolean inquotes = false;
    boolean started = false;
    while (ch>=0) {
        if (inquotes) {
            started=true;
            if (ch == '\"') {
                inquotes = false;
            }
            else {
                curVal.append((char)ch);
            }
        }
        else {
            if (ch == '\"') {
                inquotes = true;
                if (started) {
                    // if this is the second quote in a value, add a quote
                    // this is for the double quote in the middle of a value
                    curVal.append('\"');
                }
            }
            else if (ch == ',') {
                store.add(curVal.toString());
                curVal = new StringBuffer();
                started = false;
            }
            else if (ch == '\r') {
                //ignore LF characters
            }
            else if (ch == '\n') {
                //end of a line, break out
                break;
            }
            else {
                curVal.append((char)ch);
            }
        }
        ch = r.read();
    }
    store.add(curVal.toString());
    return store;
}

Есть много преимуществ для этого подхода. Обратите внимание, что каждый персонаж трогается ТОЧНО один раз. Впереди нет прочтения, отталкивания назад в буфере и т.д. Не нужно искать до конца строки, а затем копировать строку перед разбором. Этот анализатор работает исключительно из потока и создает каждое строковое значение один раз. Он работает с строками заголовков и линиями данных, вы просто имеете дело с возвращаемым списком, соответствующим этому. Вы даете ему читателя, поэтому базовый поток был преобразован в символы с использованием любой выбранной вами кодировки. Поток может поступать из любого источника: файл, HTTP-сообщение, HTTP-получение и прямой анализ потока. Это статический метод, поэтому нет объекта для создания и настройки, и когда это возвращается, память не удерживается.

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

Ответ 3

Мой подход не должен начинаться с написания вашего собственного API. Жизнь слишком коротка, и есть более насущные проблемы, которые нужно решить. В этой ситуации я обычно:

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

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

Ответ 4

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

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

Ответ 5

Мне пришлось использовать парсер csv около 5 лет назад. Кажется, существует по крайней мере два стандарта csv: http://en.wikipedia.org/wiki/Comma-separated_values и что Microsoft делает в excel.

я нашел этот libaray, который ест оба: http://ostermiller.org/utils/CSV.html, но afaik, у него нет способа вывести, какой тип данных были столбцами.

Ответ 6

Я согласен с @Brian Clapper. Я использовал SuperCSV как парсер, хотя у меня были смешанные результаты. Мне нравится его универсальность, но в моих собственных файлах csv есть некоторые ситуации, для которых я еще не смог примирить "все же". Я верю в этот продукт и рекомендую его в целом - я просто пропустил что-то простое, без сомнения, что я делаю в своей собственной реализации.

SuperCSV может анализировать столбцы в различных форматах, редактировать изменения в столбцах и т.д. Это стоит посмотреть. У него также есть примеры и легко следовать.

Единственное ограничение, которое у меня есть, - это поймать "пустой" столбец и разбор его в Целое или, возможно, пробел и т.д. Я получаю ошибки с нулевым указателем, но javadocs предлагают, чтобы каждый cellProcessor сначала проверял значения null, Итак, сейчас я обвиняю себя в этом.: -)

В любом случае, взгляните на SuperCSV. http://supercsv.sourceforge.net/

Ответ 7

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

Ответ 8

В основном вам нужно будет прочитать файл по строкам.

Затем вам нужно разделить каждую строку на разделитель, например запятую (CSV означает значения, разделенные запятыми), с

String[] strArr=line.split(",");

Это превратит его в массив строк, который вы затем можете манипулировать, например, с помощью

String name=strArr[0];
int yearOfBirth = Integer.valueOf(strArr[1]);
int monthOfBirth = Integer.valueOf(strArr[2]);
int dayOfBirth = Integer.valueOf(strArr[3]);
GregorianCalendar dob=new GregorianCalendar(yearOfBirth, monthOfBirth, dayOfBirth);
Student student=new Student(name, dob); //lets pretend you are creating instances of Student

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

Ответ 9

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

  • Чтение строковых данных из CSV
  • Преобразование строковых данных в соответствующий формат

Как только вы это сделаете, должно быть довольно тривиально использовать одну из библиотек, на которые вы ссылаетесь (что, безусловно, будет обрабатывать задачу № 1). Затем перебираем возвращаемые значения и преобразуем каждое значение String в нужное значение.

Если вопрос заключается в том, как преобразовать строки в разные объекты, он будет зависеть от того, с какого формата вы начинаете, и от какого формата вы хотите завершить.

DateFormat.parse(), например, будет анализировать даты из строк. См. SimpleDateFormat для быстрого построения DateFormat для определенного строкового представления. Integer.parseInt() будет целовать целые числа из строк.

Валюта, вам придется решить, как вы хотите ее захватить. Если вы хотите просто захватить как float, то Float.parseFloat() выполнит трюк (просто используйте String.replace(), чтобы удалить все $и запятые перед его синтаксическим анализом). Или вы можете проанализировать BigDecimal (так что у вас нет проблем округления). Там может быть лучший класс для обработки валюты (я этого не делаю, поэтому не знаком с этой областью JDK).

Ответ 10

Написание собственного анализатора - это весело, но, скорее всего, вам стоит взглянуть на Открыть CSV. Он предоставляет множество способов доступа к CSV, а также позволяет создавать CSV. И он правильно справляется с экранами. Как упоминалось в другом сообщении, в Apache Commons есть также библиотека CSV-parsing, но она еще не выпущена.