csv格式文件解析失败_从CSV文件解析不同类型的数据格式

I am still a beginner with Java programming so I apologise in advance if I am over-complicating my problem.

What is my program?

I am building a GUI based program. The goal of the program is to load a CSV, XML or JSON file and for the program to then store the data into an Array. The data will then be displayed in a text box. Ultimately, the program will have the ability to plot data to a graph.

GUI Details:

3 Radio buttons - Allows the user to select CSV, XML OR JSON

Load File Button

Display Button - Displays the data into the textArea

Display Graph Button

Text Area

Problem: I am having trouble storing the data into an Array. I believe this is because of the format of the data. So for example, this is the first 3 lines of the CSV file:

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

(Note - there are 52789000 lines of data in the CSV/XML/JSON files)

The CSV-Reader Class contains the method for reading through the data, storing it into an array and then storing it to a dataList.

As you can see from the above example, some of the data types are much different. I am having particular trouble with splitting/parsing the time and date variables.

Here is what my CSV-Reader Class code looks like at the moment (Again, I apologise for noob code).

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 dataList = new ArrayList();

private String path;

public List 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

}

Any help would be greatly appreciated!

Edit 1 - I thought that date and time were seperate CSV headers. They were not. Therefore the time variable has been deleted from the program. It has been replaced with the datetime variable.

Edit 2 - My program is now reading the CSV file up until line 15 of the csv

27000, 1273010280, 2010/5/4 21:58:0, 288, 77.74, 3.88

CONSOLE ERRORS

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)

解决方案

ISO 8601

SOLVED So the program was crashing due to my CSV not following the correct date and time format (Read comments below).

When exchanging date-time values as text, use the standard ISO 8601 formats rather than inventing your own. They are wisely designed to be easy to parse by machine and easy to read by humans across cultures. So, 2010-05-04T21:57:34, not 2010/5/4 21:57:34.

The java.time classes use the ISO 8601 formats by default when parsing/generating strings.

Data types

Date-time

The 2nd and 3rd columns of your data feed represent the same thing: a date with time-of-day. The first is a count of whole seconds since the epoch reference date of 1970-01-01T00:00Z (Z means UTC).

So it is silly to include both. As mentioned above, the 3rd column is in a poorly chosen format. The 2nd column approach of using a count-from-epoch is also a poor choice in my opinion, as it is not obvious, no human can decipher its meaning, and so it makes mistakes non-obvious thereby making debugging and logging difficult.

To deal with what we have, the seconds-from-epoch can be parsed as an Instant. This class represents a moment in UTC.

Instant instant = Instant.ofEpochMilli( 1_273_010_254L ) ;

Your 3rd column gives a date and time but omits an indicator of time zone or offset-from-UTC. Since it matches the 2nd column when parsed as seconds from first moment of 1970 in UTC, we know its value was intended for UTC. Omitting such info is bad practice, like having a monetary amount with no indicator of currency.

Ideally both columns should be replaced by a string in ISO 8601 format, for example 2010-05-04T21:57:34Z including the Z to indicate UTC.

If we had to parse the 3rd column without knowing it was intended for UTC, we would parse as a LocalDateTime, a date with time-of-day but lacking a time zone or offset. We need to define a formatting pattern to match your input.

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

LocalDateTime localDateTime = LocalDateTime.parse( "2010/5/4 21:57:34" , f );

BigDecimal

Your decimal fraction numbers should be represented as BigDecimal objects for accuracy. Never use double/Double or float/Float where you care about accuracy. These types use floating-point technology which trades away accuracy for speed of execution. In contrast, BigDecimal is slow but accurate.

Parse a BigDecimal from a string.

new BigDecimal ( "78.32" )

Apache Commons CSV

Do not write code when well-tested code already exists. There are libraries already written to read CSV/Tab-delimited files.

I use Apache Commons CSV for such work. There are several variations of these formats, all handled by this library.

Here is example code. First define a class to hold your data, here named 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 +

'}';

}

}

Example data file:

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

And now call upon Commons CSV to parse that data, instantiate Reading objects, and collect them.

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

Regarding your mention:

store the data into an Array

You are using an ArrayList in your code, not an array. See the Oracle Tutorials for lists and for arrays to understand the difference. Generally best to use the Java Collections framework. Where size and speed really matter, we may choose an array.

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.

Java 9 adds some minor features and fixes.

Java SE 6 and Java SE 7

Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.

Android

Later versions of Android bundle implementations of the java.time classes.

For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值