我试图在日志中读取两行,比较时间,然后得到两者之间的差异。例如输入文件......
20 Mar 2012 19:10:33
20 Mar 2012 19:10:34
在我得到它们之后,我会在我的程序中转到Thread.Sleep(difference)
。我的问题是:我不确定如何同时读取文件的两个不同行。
非常感谢任何和所有帮助。谢谢你的时间!
答案 0 :(得分:0)
你好像被困在一起阅读线对的想法。无需同时阅读。阅读一行,然后阅读下一行。您现在有一对要处理的输入。然后继续阅读下一行和之后的那一行。再次处理。 Lather, rinse, repeat.
也许您担心从存储中读取的性能影响。 BufferedReader
实现处理有效读取存储的挑战,缓冲来自缓存内存中文件的数据块。所以你的线对可能已经在记忆中了。您可以调整缓冲区的数量,但默认值通常很好。 BufferedReader
通常每秒可以读取数百万行,因此不太可能是真正的问题。小心premature optimization。
如果您真的关心性能,请使用java.nio.file.Files.readAllLines
一次将所有行读入内存。但是,显然,您必须有足够的可用内存来容纳输入文件的大小。因此,如果出现意外的大文件,BufferedReader
会更安全。
在这个示例代码中,我们将每对行标记为奇数编号和偶数编号,假设我们期望对。
在存储中查找您的文件。我的home folder已将log.txt
命名为<{1}}。
// Locate file in storage.
String homeFolder = System.getProperty ( "user.home" );
String fileName = "log.txt";
Path p = FileSystems.getDefault ().getPath ( homeFolder , fileName );
定义DateTimeFormatter
以匹配输入数据的预期格式。请注意,我们使用的是现代java.time类。避免旧的遗留日期时间类,这些类已被证明非常混乱和麻烦。
您的数据文件中使用的格式非常糟糕:假设英语,使用不正确的缩写词滥用英语,并且难以使用SPACE字符进行解析。我强烈建议在生成表示日期时间值的字符串时使用标准ISO 8601格式,而不是发明这样的模式。
// Define parser for expected format of data in file.
// Bad choice of format. Should have written data in standard ISO 8601 format instead.
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd MMM uuuu HH:mm:ss" , Locale.US );
连续读取线对。解析每对输入。由于输入数据遗憾地没有任何偏离UTC或时区的指示,我们解析为LocalDateTime
。
它们之间的经过时间将使用通用的24小时工作日计算Duration
,同时忽略夏令时(DST)等异常情况。最好使用具有显式偏移或时区的值,遗漏让我们想知道这些日期时间输入的真正含义。
// Read through the lines in the file, reading pairs of odd-numbered and even-numbered lines for start and stop moments.
try ( BufferedReader reader = Files.newBufferedReader ( p , StandardCharsets.UTF_8 ) ) {
String lineOdd, lineEven;
while ( ( lineOdd = reader.readLine () ) != null ) {
if ( ( lineEven = reader.readLine () ) != null ) {
LocalDateTime ldtStart = LocalDateTime.parse ( lineOdd , f );
LocalDateTime ldtStop = LocalDateTime.parse ( lineEven , f );
Duration duration = Duration.between ( ldtStart , ldtStop );
long millis = duration.getSeconds ();
int nanos = duration.getNano ();
System.out.println ( "ldtStart: " + ldtStart + " | ldtStop: " + ldtStop + " | duration: " + duration + " | Sleep for millis: " + millis + " + nanos: " + nanos );
// Thread.sleep ( millis , nanos );
} else { // Else even-numbered line was null. We expect pairs of input lines for start-stop moments.
System.out.println ( "ERROR - Failed to find even-numbered line for stop-moment." );
}
}
} catch ( IOException x ) {
System.err.format ( "IOException: %s%n" , x );
}
鉴于此数据:
20 Mar 2012 19:10:33
20 Mar 2012 19:10:34
20 Mar 2012 19:10:41
20 Mar 2012 19:10:55
20 Mar 2012 19:11:02
20 Mar 2012 19:11:22
......跑步时......
ldtStart:2012-03-20T19:10:33 | ldtStop:2012-03-20T19:10:34 |持续时间:PT1S |毫安睡眠:1 + nanos:0
ldtStart:2012-03-20T19:10:41 | ldtStop:2012-03-20T19:10:55 |持续时间:PT14S |毫安睡眠:14 + nanos:0
ldtStart:2012-03-20T19:11:02 | ldtStop:2012-03-20T19:11:22 |持续时间:PT20S |毫安睡眠:20 + nanos:0
如果您的输入文件是为了代表时间轴上的一对时刻,那么请将它们记录下来。 ISO 8601标准将间隔定义为与SOLIDUS(斜杠)字符连接的一对日期时间字符串。
如上所述,对每个日期时间值使用标准ISO 8601格式。始终包含具有此类值的UTC偏移量或时区。当您打算将UTC作为偏移量时,您只需附加一个Z
,即Zulu
的缩写。
Instant
因此20 Mar 2012 19:10:33
变为2012-03-20T19:10:33Z
。 2012-03-20T19:10:33Z
之类的值可以作为Instant
对象处理。 Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds。
标准格式的对将是2012-03-20T19:10:33Z/2012-03-20T19:10:34Z
。所以你的输入文件应该是:
2012-03-20T19:10:33Z/2012-03-20T19:10:34Z
2012-03-20T19:10:41Z/2012-03-20T19:10:55Z
2012-03-20T19:11:02Z/2012-03-20T19:11:22Z
Interval
此类区间对可以通过Interval
项目中的ThreeTen-Extra类表示为对象。该项目扩展了Java中构建的java.time类。该项目也是未来可能添加到java.time的试验场。
Interval interval = Interval.of( start , stop );
Interval
类可以解析并生成直接显示的行,因为它们完全符合ISO 8601.无需指定任何格式化模式。
String output = interval.toString(); // Example: 2012-03-20T19:10:33Z/2012-03-20T19:10:34Z
......或走向另一个方向......
Interval interval = Interval.parse( "2012-03-20T19:10:33Z/2012-03-20T19:10:34Z" );
您可以从Duration
获得Interval
。
Duration duration = interval.toDuration();
那么Interval
和Duration
之间有什么区别?第一个与时间轴上的特定时刻相关联;第二个没有附加到时间表。
PnYnMnDTnHnMnS
同样,如果您希望将持续时间记录为未附加到时间轴的时间段,请让Duration
类读取并写入PnYnMnDTnHnMnS
标准ISO 8601 format for durations P
标记开头,T
分隔任何年 - 月 - 天与小时 - 分 - 秒。您在上面的示例输出中看到此格式由Duration::toString
方法生成。例如,PT14S
是十四秒。
Duration duration = Duration.between ( start , stop );
String output = duration.toString(); // Example: PT14S
......走向另一个方向......
Duration duration = Duration.parse( "PT14S" );
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date
,.Calendar
和&amp; java.text.SimpleDateFormat
。
现在位于Joda-Time的maintenance mode项目建议迁移到java.time。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。
大部分java.time功能都被反向移植到Java 6&amp; ThreeTen-Backport中的7,并进一步适应Android中的ThreeTenABP(见How to use…)。
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
等。