【问题标题】:Turning a remote file into an input stream over HTTP in Java在 Java 中通过 HTTP 将远程文件转换为输入流
【发布时间】:2023-03-15 16:07:01
【问题描述】:

我有一个文本文件的 URL,我希望我的 Java 程序读取该文本文件。 但是剧情变厚了!该文件不断添加新行,我想在这些行进入时阅读它们。

我认为正确的方法是打开一个指向文件 URL 的 URLConnection,并以某种方式将该 URLConnection 置于某种 StreamReader 或 StreamBuffer 类型的对象的“监督”之下。

这就是我的 Java 技能受到质疑的地方,我想知道是否有人愿意提供一两个答案。

谢谢。

【问题讨论】:

    标签: java http file stream


    【解决方案1】:

    URLConnection 中获取InputStream 并将其包装在InputStreamReader 中,然后将ISR 包装在BufferedReader 中:

    InputStream is = urlConnection.getInputStream();
    InputStreamReader isr = new InputStreamReader(is, <encoding>);
    BufferedReader br = new BufferedReader(isr);
    

    您现在可以使用br.readLine() 从资源中读取每一行文本,直到它返回 null (EOF)。但是,您必须从某个地方获取字符编码,无论是从 HTTP 响应内容类型标头还是已知的,您都可以直接指定它。

    【讨论】:

    • 这将读取文件一次,仅此而已。据我了解,OP 正在寻找“tail -f”的 java 等价物
    【解决方案2】:

    要实现一个 InputStream,您需要在一个循环中发出多个 http 请求,并跟踪到目前为止您已经阅读了多少,以便流的使用者获得 一致的输出。

    伪代码:

    int read_bytes = 0;
    while (should_be_reading) {
      # make http request
    
      # read or scan to read_bytes
      # emit any new bytes
      # update read_bytes
    
    }
    

    【讨论】:

    • 这正是我所做的——我只是想知道这是否意味着我每次发出 http 请求时都在下载整个文件。
    • 每次都会请求整个文件。如果网络服务器支持 HTTP/1.1 范围标头,则可以通过告诉服务器仅在某个字节偏移后发送内容来提高效率。 w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
    【解决方案3】:

    如果您跟踪读取的总字节数,您可以使用 http 范围标头告诉服务器从给定位置开始提供文件。此功能主要用于恢复下载,但应该适用于此。

    我意识到这不会给你一个输入流,但我认为这是一个更强大的解决方案。

    【讨论】:

    • 所有 Web 服务器和配置都支持范围标头吗? (我问是因为有时我知道你无法恢复下载)也许他仍然需要回退到一遍又一遍地阅读整个文件以保持健壮性
    • 不,不是,但 Warlax 只需要在 1 台服务器上支持它。虽然不能保证范围支持,但我认为这是常态,如今无法恢复下载的情况非常罕见。最有可能无法恢复的情况是,内容由动态应用程序而非静态文件提供。
    【解决方案4】:

    根据上面的cmets,我想我已经解决了这个问题。 我只是不太确定这并不意味着我每次都在下载整个文件:

                    long charsRead = 0;
    
                    while(keepRunning)
                    {
                        URL url = new URL(finalUrlString);
                        URLConnection connection = url.openConnection();
                        InputStreamReader stream = new InputStreamReader(connection.getInputStream());
                        BufferedReader reader = new BufferedReader(stream);
                        long skipped = reader.skip(charsRead);
                        String line = reader.readLine();
                        if(line != null)
                        {
                            charsRead += line.length() + 1;
                            process(line);
                        }
                        reader.close();
                    }
    

    这段代码在它自己的线程中运行。我正在使用 process 方法来填充通过解析每一行生成的对象向量。

    不同的代码,在不同的线程上,查看这个向量 - 读取对象 - 并清空它。

    当然这个线程和另一个线程是围绕那个向量实例同步的。

    【讨论】:

      猜你喜欢
      • 2017-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多