【问题标题】:Reading end of huge and dynamic file via SFTP from server通过 SFTP 从服务器读取巨大动态文件的结尾
【发布时间】:2018-03-27 14:37:41
【问题描述】:

我正在尝试找到一种方法,通过 SFTP 从服务器读取巨大和动态日志文件的末尾(例如从末尾开始的 20-30 行),并将该点保存到我读取的位置,如果我需要更多行,从这里开始阅读更多内容。

我尝试的所有操作都需要很长时间,我尝试在机器上复制此文件,然后使用ReversedLinesFileReader 从末尾读取,因为此方法需要File 对象,当通过 SFTP 时,您将获得只有InputStream,下载文件需要很多时间。

还尝试计算行数并从 n 行读取,但也花费了太长时间并引发异常,因为此时文件被修改。我尝试通过 SSH 连接并使用 tail -100 并获得所需结果的另一种方式,但只是一次,因为下次我也会获得新日志,但我需要更上一层楼。有没有一种快速的方法来获取文件的结尾并保存该点并稍后阅读更多内容?有什么想法吗?

【问题讨论】:

  • 我建议您创建一个摘要过程,将整体日志文件拆分为每个文件可能 5000 行的小文件,并根据您要访问它们的顺序对它们进行排序/排序。这应该会让你的工作变得轻松一些。
  • 不是真正的直接响应,而是更像是头脑风暴,并且高度依赖于您的要求和基础设施,但您可能会考虑引入elastic search a/o logstash(或类似的能力)像这样的工作的工具)?然后,您可以使用可用的 API 根据您的条件检索数据,例如 date-range

标签: java sftp


【解决方案1】:

你没有说你使用的是什么 SFTP 库,但使用最广泛的 Java SSH/SFTP 库是JSch,所以我假设你正在使用它。

SFTP protocol 具有对远程文件执行随机访问 I/O 的操作。不幸的是,JSch SFTP 客户端并未公开所有操作。但是,它确实具有允许跳过远程文件的第一部分的get operation 版本(用于从远程服务器获取文件)。例如,您可以使用其中一种操作来读取文件的最后 10 KB。

几个 JSch get 操作返回一个 InputStream。您可以从输入流中读取远程文件的内容。如果要逐行访问远程文件,可以使用InputStreamReader将其转换为Reader

因此,进程可能会执行以下操作:

  1. 在远程文件上调用stat() 以获取其大小。
  2. 找出要从文件中的哪个位置开始读取。您可以跟踪上次停止阅读的位置,或者您可以根据您愿意下载的数据量以及最后 20-30 行的预期大小(以字节为单位)进行猜测。
  3. 致电get() 开始阅读。
  4. 处理从InputStream 读取的数据,由get() 调用返回。

【讨论】:

    【解决方案2】:

    最好有一种旋转日志文件,可能带有压缩。

    Hower rsync 是一种单向同步,它只能传输文件的更改部分:对于日志来说是新的结束。

    我不确定它在您的情况下是否足够高效,ssh 是先决条件。

    【讨论】: