【问题标题】:Javascript: Reading only the last x amount of lines of large server text fileJavascript:仅读取大型服务器文本文件的最后 x 行
【发布时间】:2014-06-30 15:33:27
【问题描述】:

今天我正在处理非常大的日志文件,我想通过 lighttpd 在我的 RPi 上显示它们,但它们每天都在变大,因此很快就会需要很长时间才能加载。

为了防止这个问题,我想我可以有一个按钮来读取,比如这个日志文件的最后 500 行。当然我对javascript没有太多经验,但我认为它是可行的,对吧?

无论如何,虽然我在 PHP 中找到了this,但我找不到任何描述如何在 javascript 中执行此操作的好教程,但由于我不是在 PHP 中工作,所以我无法使用它。因此,一个关于如何在 javascript 中读取最后 500 行的示例,或者每次单击从文件末尾开始的按钮时逐步读取 500 行的按钮对我来说非常少。

提前谢谢各位。

P.S:我已经读过使用 javascript 无法读取文件,但使用 AJAX 调用是可能的。)

【问题讨论】:

  • 我认为这是不可能的。为什么不能使用 PHP?当您向服务器请求(请求)文件时,服务器最终必须发送整个文件。
  • @soktinpk 它为我的 RPi 提供了更多的配置,我希望它尽可能简单,如果这不可能,我可能还是不得不使用 PHP..
  • 那么,我能想到的唯一方法就是手动将大文件拆分为 500 行的单独块。
  • 我同意soktinpk。只需使用 AJAX 向服务器发出请求,然后使用服务器端语言仅输出文件的最后 50 行。如果您使用 PHP,那么您可以使用 PHP 将数据保存在数据库中,并在输出文件中仅获取数据库中的最后 50 项。
  • 这里有很多选择——如果你想要一个简单的例子来说明如何调用用 Python 编写的服务器端 CGI(在 RPi 上使用 lighttpd 托管),我实际上基于它创建了一个项目一年前:github.com/swlasse/RPiDeskController。但是,是的,基本上,您需要使用例如 jQuery 进行 AJAX 请求,有一个端点监听,处理请求,并解析您在客户端返回的响应。

标签: javascript jquery ajax large-files


【解决方案1】:

不,JavaScript 不可能。客户端在统一资源定位器上请求资源 - 如果这是所需的响应,则由您的服务器提供最后 500 行。

如果您无法使用 PHP,简单的 unix 命令 tail -500 mylog 可以被多种服务器端脚本语言解释。

【讨论】:

  • 感谢您的建议,似乎需要额外的配置才能让 PHP 正常工作,我如何轻松地从 PHP 调用 unix 命令?
【解决方案2】:

严格来说,您可能可以通过发出两个 HTTP 请求来做到这一点:

  1. 发出HEAD 请求,该请求应返回Content-Length 标头,该标头告诉您文件的大小。
  2. 执行带有Content-Range 标头的GET 请求以请求文件的最后N 个字节。

当然,这仅适用于文件中的行倾向于保持接近特定平均长度的情况。因此,如果您知道文件中的行往往有大约 100 个字节,并且您想要最后 20 行,那么您可以请求最后一个,比如说,2,400 个字节(20 行 ✕ 100 字节 + 20% 为好衡量标准)。然后您可以解析响应以获取最后 20 行。

这是未经测试的(因为我没有方便的服务器来测试)并且没有任何错误处理,但是这样的东西应该可以工作,假设 lighttpd 被配置为返回带有响应的 Content-Range 标头到 HEAD 请求:

var url = "http://example.com/some-file.txt",
    averageLineLength = 100,
    numLinesToFetch   = 20,
    marginForError    = 0.2,
    bytesToFetch      = averageLineLength * numLinesToFetch * (1 + marginForError)
;

$.ajax({ url: url, type: "HEAD" })
  .then( function(_, _, xhr) {
    var fileSize = parseInt(xhr.getResponseHeader('Content-Length')),
        contentRangeStart = fileSize - bytesToFetch,
        contentRangeEnd   = fileSize - 1,
        contentRange      = contentRangeStart + "-" + contentRangeEnd + "/" + fileSize,
        headers           = { "Content-Length": bytesToFetch,
                              "Content-Range":  "bytes " + contentRange }
    ;

    return $.ajax({ url: url, type: "GET", headers: headers });
  } )
  .then( function(data, statusText, xhr) {
    var lines = data.split("\n");
    lines = lines.slice(numLinesToFetch * -1);
    console.log( "Last " + numLinesToFetch + " lines:\n",
                 lines );
  } )
;

这有点令人费解,每次都需要请求额外的数据(如果您获得大量数据,则会对内存产生影响,尤其是对于幼稚的data.split),我不确定是否配备了 lighthttp开箱即用,但这是一个想法!

【讨论】:

  • 感谢您的建议,但可能需要更多时间来实现类似的东西,然后为 lighttpd 设置 PHP 并对其进行配置等。
  • @Linus 这可以理解,尽管我写示例代码确实很有趣。
【解决方案3】:

如果您手头有 Ruby,这里有一个快速 CGI 脚本,可以执行上面 cmets 中讨论的操作:

#!/usr/bin/env ruby
require "cgi"

NUM_LINES    = 20
FILE_TO_TAIL = "/var/log/system.log"
COMMAND      = "| tail -#{NUM_LINES} #{FILE_TO_TAIL}"

cgi = CGI.new
open(COMMAND) {|io| cgi.out("text/plain", &io.method(:read)) }

这里是 a lighttpd configuration(不是我的),它显示了如何将 lighttpd 指向脚本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 2012-10-31
    • 2012-07-22
    • 2022-11-02
    • 1970-01-01
    • 2011-05-30
    • 2020-12-08
    相关资源
    最近更新 更多