Анализ различных типов формата данных из файла CSV - PullRequest
0 голосов
/ 25 ноября 2018

Я все еще новичок в программировании на Java, поэтому заранее прошу прощения, если я слишком усложняю свою проблему.

Какая у меня программа? Я строю программу на основе графического интерфейса.Цель программы - загрузить файл CSV, XML или JSON, а затем сохранить данные в массиве.Данные будут отображаться в текстовом поле.В конечном счете, программа будет иметь возможность наносить данные на график.

Подробности графического интерфейса:

  • 3 Радиокнопки - Позволяет пользователю выбирать CSV, XML ИЛИ JSON
  • Кнопка загрузки файла
  • Кнопка отображения - отображает данные в текстовой области
  • Отображение кнопки графика
  • Текстовая область

Проблема: У меня проблемахранение данных в массиве.Я считаю, что это из-за формата данных.Например, это первые 3 строки файла CSV:

millis,stamp,datetime,light,temp,vcc
1000, 1273010254, 2010/5/4 21:57:34, 333, 78.32, 3.54
2000, 1273010255, 2010/5/4 21:57:35, 333, 78.32, 3.92
3000, 1273010256, 2010/5/4 21:57:36, 344, 78.32, 3.95

(Примечание. В файлах CSV / XML / JSON 52789000 строк данных)

CSV-Reader Class содержит метод для чтения данных, сохранения их в массиве и последующего сохранения в dataList.

Как видно из приведенного выше примера, некоторые типы данных сильно отличаются.У меня особые проблемы с разделением / анализом переменных времени и даты.

Вот как выглядит мой код класса CSV-Reader на данный момент (опять же, я прошу прощения за код noob).

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CSVReader {

//create a class that will hold arraylist which will have objects representing all lines of the file

private List<Data> dataList = new ArrayList<Data>();
private String path;

public List<Data> getDataList() {
    return dataList;
}

public String getPath() {
    return path;
}
public void setPath(String path) {
    this.path = path;
}

//Create a method to read through the csv stored in the path
//Create the list of data and store in the dataList

public void readCSV() throws IOException{

    //i will create connection with the file, in the path
    BufferedReader in  = new BufferedReader(new FileReader(path));  

    String line = null;
    line = in.readLine();

    while((line = in.readLine())!=null){

        //I need to split and store in the temporary variable and create an object


        String[] splits = line.split("\\s*(=>|,|\\s)\\s*");

        long millis = Long.parseLong(splits[0].trim());
        long stamp = Long.parseLong(splits[1].trim());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
        System.out.println(splits[2].trim());
        LocalDateTime dateTime = LocalDateTime.parse(splits[2].trim(), formatter);
        LocalDate dateTime = dateTime.toLocalDate();
        LocalTime time = dateTime.toLocalTime();
        int light = Integer.parseInt(splits[3].trim());
        double temp = Double.parseDouble(splits[4].trim());
        double vcc = Double.parseDouble(splits[5].trim());

        Data d = new Data(millis,stamp,datetime,light,temp,vcc);//uses constructor


        //final job is to add this object 'd' onto the dataList
        dataList.add(d);

    }//end of while loop

}

Любая помощь будет принята с благодарностью!

Редактировать 1 - я думал, что дата и время были отдельными заголовками CSV.Они не были.Поэтому переменная времени была удалена из программы.Он был заменен переменной datetime.

Редактировать 2 - Моя программа теперь читает файл CSV вплоть до строки 15 csv

27000, 1273010280, 2010/5/4 21: 58: 0, 288, 77,74, 3,88

ОШИБКИ КОНСОЛИ

Exception in thread "AWT-EventQueue-0" 
java.time.format.DateTimeParseException: Text **'2010/5/4 21:58:0'** could not 
be parsed at index 15
at java.time.format.DateTimeFormatter.parseResolved0(Unknown Source)
at java.time.format.DateTimeFormatter.parse(Unknown Source)
at java.time.LocalDateTime.parse(Unknown Source)
at CSVReader.readCSV(CSVReader.java:55)
at GUI$2.actionPerformed(GUI.java:85)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

Ответы [ 4 ]

0 голосов
/ 26 ноября 2018

ISO 8601

РЕШЕНО Таким образом, программа зависала из-за того, что мой CSV не соблюдал правильный формат даты и времени (см. Комментарии ниже).

При обмене датой-время значения в виде текста, используйте стандартные форматы ISO 8601 , а не придумывать свои собственные.Они продуманно разработаны для того, чтобы их было легко разобрать на машине и легко прочитать людям в разных культурах.Итак, 2010-05-04T21:57:34, а не 2010/5/4 21:57:34.

Классы java.time по умолчанию используют форматы ISO 8601 при разборе / генерации строк.

Типы данных

Дата-время

2-й и 3-й столбцы вашего фида данных представляют одно и то же: дату с временем дня.Первая - это число полных секунд с даты начала отсчета 1970-01-01T00: 00Z (Z означает UTC).

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

Чтобы разобраться с тем, что у нас есть, секунды от эпохи можно проанализировать как Instant.Этот класс представляет момент в UTC.

Instant instant = Instant.ofEpochMilli( 1_273_010_254L ) ;

В 3-м столбце указаны дата и время, но не указан индикатор часового пояса или смещения от UTC.Поскольку он соответствует 2-му столбцу при разборе в секундах с первого момента 1970 года в формате UTC, мы знаем, что его значение предназначено для UTC.Пропуск такой информации - плохая практика, например, наличие денежной суммы без указания валюты.

В идеале оба столбца следует заменить строкой в ​​формате ISO 8601, например, 2010-05-04T21:57:34Z, включая Z, чтобы указатьUTC.

Если бы нам пришлось анализировать 3-й столбец, не зная, что он предназначен для UTC, мы бы проанализировали как LocalDateTime, дату с временем дня, но без часового пояса или смещения.Нам нужно определить шаблон форматирования, соответствующий вашему вводу.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu/M/d HH:mm:ss" );
LocalDateTime localDateTime = LocalDateTime.parse( "2010/5/4 21:57:34" , f );

BigDecimal

Ваши десятичные дробные числа должны быть представлены как BigDecimal объекты для точности.Никогда не используйте double / Double или float / Float там, где вам важна точность.Эти типы используют технологию с плавающей точкой , которая меняет точность на скорость выполнения.Напротив, BigDecimal медленный, но точный.

Разбор BigDecimal из строки.

new BigDecimal ( "78.32" ) 

Apache Commons CSV

Не пишите код, когда хорошопроверенный код уже существует.Существуют библиотеки, уже написанные для чтения CSV / Разделенных табуляцией файлов.

logo for the Apache Commons CSV project

I use Apache Commons CSV за такую ​​работу.Существует несколько вариантов этих форматов, все они обрабатываются этой библиотекой.

Вот пример кода.Сначала определите класс для хранения ваших данных с именем Reading.

Reading.java

package com.basilbourque.example;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;

public class Reading {
    private Integer millis;
    private Instant instant;
    private LocalDateTime localDateTime;
    private Integer light;
    private BigDecimal temp;
    private BigDecimal vcc;

    public Reading ( Integer millis , Instant instant , LocalDateTime localDateTime , Integer light , BigDecimal temp , BigDecimal vcc ) {
        // TODO: Add checks for null arguments: Objects.requireNonNull( … ).
        this.millis = millis;
        this.instant = instant;
        this.localDateTime = localDateTime;
        this.light = light;
        this.temp = temp;
        this.vcc = vcc;
    }

    @Override
    public String toString ( ) {
        return "com.basilbourque.example.Reading{" +
                "millis=" + millis +
                ", instant=" + instant +
                ", localDateTime=" + localDateTime +
                ", light=" + light +
                ", temp=" + temp +
                ", vcc=" + vcc +
                '}';
    }
}

Пример файла данных:

millis,stamp,datetime,light,temp,vcc
1000, 1273010254, 2010/5/4 21:57:34, 333, 78.32, 3.54
2000, 1273010255, 2010/5/4 21:57:35, 333, 78.32, 3.92
3000, 1273010256, 2010/5/4 21:57:36, 344, 78.32, 3.95

А теперь вызовите Commons CSV для анализа этих данных, создания экземпляров Reading объектов и сбораих.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu/M/d HH:mm:ss" );

List < Reading > readings = new ArrayList <>( 3 );
Reader reader = null;
try {
    reader = new FileReader( "/Users/basilbourque/data.csv" );
    Iterable < CSVRecord > records = CSVFormat.RFC4180.withIgnoreSurroundingSpaces( true ).withHeader().parse( reader );
    for ( CSVRecord record : records ) {
        // Grab inputs
        String millisInput = record.get( "millis" );
        String stampInput = record.get( "stamp" );
        String datetimeInput = record.get( "datetime" );
        String lightInput = record.get( "light" );
        String tempInput = record.get( "temp" );
        String vccInput = record.get( "vcc" );

        // Parse inputs
        Integer millis = Integer.valueOf( millisInput );
        Instant instant = Instant.ofEpochSecond( Integer.valueOf( stampInput ) );
        LocalDateTime localDateTime = LocalDateTime.parse( datetimeInput , f );
        Integer light = Integer.valueOf( lightInput );
        BigDecimal temp = new BigDecimal( tempInput );
        BigDecimal vcc = new BigDecimal( vccInput );

        // Construct object
        Reading r = new Reading( millis , instant , localDateTime , light , temp , vcc );

        // Collect object
        readings.add( r );
    }
} catch ( FileNotFoundException e ) {
    e.printStackTrace();
} catch ( IOException e ) {
    e.printStackTrace();
}

System.out.println( readings );

[com.basilbourque.example.Reading {millis = 1000, instant = 2010-05-04T21: 57: 34Z, localDateTime = 2010-05-04T21: 57: 34, light = 333, temp = 78.32, vcc = 3.54}, com.basilbourque.example.Reading {millis = 2000, instant = 2010-05-04T21: 57: 35Z, localDateTime = 2010-05-04T21: 57: 35,light = 333, temp = 78.32, vcc = 3.92}, com.basilbourque.example.Reading {millis = 3000, instant = 2010-05-04T21: 57: 36Z, localDateTime = 2010-05-04T21: 57: 36, light= 344, temp = 78.32, vcc = 3.95}]

По поводу вашего упоминания:

сохранить данные в массиве

Youв вашем коде используется ArrayList, а не массив.Смотрите Oracle Tutorials для списков и для массивов , чтобы понять разницу.Обычно лучше всего использовать Java Collections framework .Если размер и скорость действительно имеют значение, мы можем выбрать массив.


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами непосредственно с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинство функций java.time перенесено в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии пакетов Android для реализации java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

0 голосов
/ 25 ноября 2018
  1. кажется, у вас есть 5 токенов в одной строке (не 6),

  2. вы пытаетесь проанализировать строку даты как двойную,

с некоторыми изменениями в вашем коде, после одной работы для вас:

String[] splits = line.split(",");// line.split("\\s*(=>|,|\\s)\\s*");

long millis = Long.parseLong(splits[0].trim());
long stamp = Long.parseLong(splits[1].trim());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(splits[2].trim(), formatter);
LocalDate date = dateTime.toLocalDate();
LocalTime time = dateTime.toLocalTime();
int light = Integer.parseInt(splits[3].trim());
double temp = Double.parseDouble(splits[4].trim());
double vcc = Double.parseDouble(splits[5].trim());
0 голосов
/ 25 ноября 2018

Вы пытаетесь проанализировать date как числовое, и это поле String, может быть, вы можете использовать это

Date date=new SimpleDateFormat("yyyy/M/D HH:mm:ss").parse(splits[2]);

Теперь с датой вы можете преобразовать, как вы хотите

0 голосов
/ 25 ноября 2018

Поскольку ваш столбец date является строкой, вам необходимо проанализировать его в объект даты.Это зависит от вашей версии Java;если вы используете Java 8, вы можете использовать новые классы даты.Может быть, этот ответ может помочь вам в этом.

Похоже, у вас есть два отдельных столбца, date и time в заголовке CSV, но строки имеют дату и время водин столбец.Это может быть частью вашей проблемы.Вам необходимо определить, являются ли они двумя столбцами или одним, но в любом случае они могут быть проанализированы с библиотеками Java.

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

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