Javascript:只读取大型服务器文本文件的最后x行数

时间:2014-06-30 15:33:27

标签: javascript jquery ajax large-files

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

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

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

先谢谢你们。

P.S :我读过它不可能用javascript读取文件,但是使用AJAX调用它是可能的。)

3 个答案:

答案 0 :(得分:4)

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

如果PHP无法使用,则可以通过许多服务器端脚本语言解释简单的unix命令tail -500 mylog

答案 1 :(得分:2)

严格地说,您可能能够通过发出两个HTTP请求来执行此操作:

  1. 发出HEAD请求,该请求应返回Content-Length标题,告诉您文件的大小。
  2. 使用GET标头执行Content-Range请求,以请求文件的最后 N 个字节。
  3. 当然,这仅在文件中的行倾向于接近特定平均长度时才有效。因此,如果您知道文件中的行往往有大约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),而且我不确定是否有轻微的数据开箱即用,但这是一个想法!

答案 2 :(得分:0)

如果你有Ruby方便,这里有一个快速的CGI脚本,可以完成上述评论中讨论的内容:

#!/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。