阅读之后的行

时间:2016-09-08 21:05:22

标签: java date time sleep filereader

我试图在日志中读取两行,比较时间,然后得到两者之间的差异。例如输入文件......

20 Mar 2012 19:10:33 
20 Mar 2012 19:10:34

在我得到它们之后,我会在我的程序中转到Thread.Sleep(difference)。我的问题是:我不确定如何同时读取文件的两个不同行。

非常感谢任何和所有帮助。谢谢你的时间!

1 个答案:

答案 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:3​​3 | ldtStop:2012-03-20T19:10:3​​4 |持续时间: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:33Z2012-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();

那么IntervalDuration之间有什么区别?第一个与时间轴上的特定时刻相关联;第二个没有附加到时间表。

标准时长格式: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.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date.Calendar和&amp; java.text.SimpleDateFormat

现在位于Joda-Timemaintenance 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的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter等。