应该如何修改从网络驱动器读取 5G 日志文件的 Scala 脚本以读取最后 x 行(如 Unix 中的“tail”)?
Posted
技术标签:
【中文标题】应该如何修改从网络驱动器读取 5G 日志文件的 Scala 脚本以读取最后 x 行(如 Unix 中的“tail”)?【英文标题】:How the Scala script that reads 5G log file from network drive should be modified in order to read last x lines (like 'tail' in Unix)? 【发布时间】:2009-11-03 18:31:16 【问题描述】:应如何修改从网络驱动器读取 5G 日志文件的 Scala 脚本以读取最后 x 行(如 Unix 中的“tail”)?
::#!
@echo off
call scala %0 %*
goto :eof
::!#
import scala.io.Source
if (args.length > 0)
for (line <-Source.fromFile(args(0)).getLines)
if(line.contains("percent"))
print(line)
【问题讨论】:
【参考方案1】:我在这个队列中使用了一个可变队列:
::#!@echo off
call scala %0 %*
goto :eof
::!#
import scala.io.Source
val lastN = 5 // I guess you'll be getting them from args, but...
val queue = new scala.collection.mutable.Queue[String]
if (args.length > 0)
Source.fromFile(args(0)).getLines foreach line =>
queue.enqueue(line)
if (queue.size > lastN) queue.dequeue
for (line <- queue)
if (line.contains("percent"))
print(line)
如果使用不可变队列,我会使用 reduceLeft,但我认为为此使用不可变队列毫无意义。
【讨论】:
通过网络读取整个 5G 文件并转储除最后 5 行之外的所有文件似乎并不理想。 不是。您必须从末尾读取字节块,直到获得所需的行数才能正确执行,使用几个堆栈作为行 - 一个用于当前块,一个用于整体。这需要通过 Java I/O 库,这太糟糕了,我不会不付钱就碰它。 :-) 除非你知道编码是固定字节长度的,否则不可能从文件向后读取 pumpkin 的方法,从下面来看,是这样做的唯一明智的方法,假设网络文件系统确实允许搜索。正如 Daniel 所说,这需要调用 java 库。 java.io.RandomAccessFile 有一个 readLine() 方法,可以让您直接从文件中读取字符串。只需大量备份,将行读入缓冲区或队列,直到读完,然后取最后 5 行。【参考方案2】:如果读取文件的成本很高,正如我所期望的那样,它是通过网络读取的,我会寻找文件的末尾并逐渐读取更大的块(更多关于日志文件格式的领域知识可能会给你一个更好的策略) 从最后直到找到您要查找的行数。
【讨论】:
【参考方案3】:显然,您必须保留 x 行的缓冲区,并在每次迭代时更新:
var buf: List[String] = Nil
for (line <- ...)
buf = (buf ::: List(line)) match
case x :: xs if (xs.length == n) => xs
【讨论】:
这不是像 Daniel 对可变队列所做的那样非常丑陋吗? (这也是低效的,因为 buf 必须在循环的每次迭代中以线性时间复制。) 我已经简化了比赛(为了清楚起见,我把所有的案例都放在了里面)。我认为您需要阅读 scala 的不可变数据结构,因为使用List
不会进行复制。个人觉得很优雅!
Oxbow,buf 正在在线性时间内被复制。 :::
左侧的 arg 始终被复制。 ::
不会复制任何内容。
@Daniel - 我根本看不到它,因为我只是 :::
-ing 到一个 1 元素列表!一个ListBuffer
被创建,一个元素 被复制到其中。然而,原始列表随后通过 ListBuffer.prependToTail
前置 - 这不会复制,因为 ListBuffer.toList
是一个恒定时间操作
没有。见lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_7_final/src/…。复制“那些”(即左侧项目,“buf”)的全部内容,然后将 ListBuffer 附加到“this”(右侧项目,List(line))之前。如果您要使用不可变数据结构执行此操作,至少使用 immutable.Queue,它在内部使用两个列表来获得摊销的常量时间入队和出队。以上是关于应该如何修改从网络驱动器读取 5G 日志文件的 Scala 脚本以读取最后 x 行(如 Unix 中的“tail”)?的主要内容,如果未能解决你的问题,请参考以下文章