我仍然是Java编程的初学者,因此如果我使问题变得过于复杂,我会提前道歉。
我的程序是什么? 我正在构建一个基于GUI的程序。该程序的目标是加载CSV,XML或JSON文件,然后程序将数据存储到Array中。然后,数据将显示在文本框中。最终,该程序将能够将数据绘制到图形上。
GUI详细信息:
问题:我在将数据存储到数组时遇到问题。我相信这是因为数据的格式。因此,例如,这是CSV文件的前3行:
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类包含以下方法:读取数据,将其存储到数组中,然后将其存储到dataList中。
从上面的示例中可以看到,某些数据类型有很大不同。我在拆分/解析时间和日期变量时遇到了特别麻烦。
这是我的CSV阅读器类代码目前的样子(再次,我为菜鸟代码表示歉意)。
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文件,直到csv的第15行
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)
答案 0 :(得分:1)
由于您的print(pd.to_datetime(df['date'].astype(str) + ' ' + df['time'].astype(str)))
0 2011-01-01 12:48:20
1 2014-01-01 12:30:45
dtype: datetime64[ns]
列是字符串,因此您需要将其解析为日期对象。这取决于您的Java版本。如果您使用的是Java 8,则可以使用新的日期类。也许this answer可以帮助您。
看起来您在CSV标头中有两个单独的列,date
和date
,但是这两行中的日期和时间在其中一列。这可能是您问题的一部分。您需要确定它们是两列还是一列,但是无论如何都可以使用Java库对其进行解析。
此外,最好使用经过Apache Commons CSV之类的经过战斗测试的CSV库,而不是滚动自己的CSV解析器。在有限的情况下,您可能会遇到麻烦,但是CSV并不像它第一次出现时那样简单。
答案 1 :(得分:1)
已解决,由于我的CSV格式不符合正确的日期和时间格式,因此程序崩溃了。
在将日期时间值作为文本交换时,请使用标准的ISO 8601格式,而不要发明自己的格式。明智地设计了它们,使其易于通过机器解析,并且易于跨文化的人类阅读。因此,2010-05-04T21:57:34
,而不是2010/5/4 21:57:34
。
java.time 类在解析/生成字符串时默认使用ISO 8601格式。
数据Feed的第二列和第三列表示相同的内容:带有日期的日期。第一个是自纪元参考日期1970-01-01T00:00Z(Z
表示UTC)以来的秒数。
因此同时包含这两者是很愚蠢的。如上所述,第3列的格式选择不当。在我看来,使用“从纪元计数”的第二列方法也不是一个好的选择,因为它并不明显,没有人可以理解其含义,因此错误变得不明显,从而使调试和记录变得困难。
要处理我们拥有的内容,可以将距秒的秒数解析为Instant
。该课程代表UTC的时刻。
Instant instant = Instant.ofEpochMilli( 1_273_010_254L ) ;
您的第3列给出了日期和时间,但省略了时区或UTC偏移量的指示。由于它与UTC 1970年第一时刻的秒数相匹配时与第二列匹配,因此我们知道它的值适用于UTC。忽略此类信息是不明智的做法,例如拥有一个没有货币指标的货币金额。
理想情况下,两列均应替换为ISO 8601格式的字符串,例如2010-05-04T21:57:34Z
包括Z
以表示UTC。
如果我们不得不在不知道要用于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
。这些类型使用floating-point技术trades away accuracy来提高执行速度。相反,BigDecimal
慢但准确。
从字符串中解析BigDecimal
。
new BigDecimal ( "78.32" )
在经过良好测试的代码已经存在时,请勿编写代码。已经编写了可读取CSV / Tab-delimited文件的库。
我将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} ]
关于您的提及:
将数据存储到数组
您在代码中使用的是ArrayList
,而不是数组。请参阅Oracle教程for lists和for arrays了解不同之处。通常最好使用Java Collections framework。在大小和速度真正重要的地方,我们可以选择一个数组。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:0)
似乎您在一行中有5个令牌(不是6),
您正试图将日期字符串解析为双精度,
在您的代码中进行了一些修改,以下是为您执行的一项工作:
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());
答案 3 :(得分:-1)
您正尝试将date
解析为数字,并且这是一个String字段,也许您可以使用此
Date date=new SimpleDateFormat("yyyy/M/D HH:mm:ss").parse(splits[2]);
现在有了日期,您可以根据需要进行转换