【问题标题】:Custom implementation of InputStreamInputStream 的自定义实现
【发布时间】:2011-06-15 20:48:02
【问题描述】:

要将数据发送到我的 FTP 服务器上的文件,我需要创建一个自定义 InputStream 实现,它逐行读取数据库数据,将其转换为 CSV 并通过其 read() 方法发布:从数据库中,我得到带有数据的 List<Application> 对象。对于每个Application 对象,我想在 CSV 文件中创建一行。

我的想法是在构造函数中加载所有数据,然后覆盖读取方法。我需要重写所有 InputStream 的方法吗?我尝试在谷歌上搜索一些示例,但没有成功 - 你最终能给我一个链接吗?

【问题讨论】:

标签: java ftp inputstream java-io


【解决方案1】:

您只需要实现the read() method without parameters。所有其他方法都作为对该方法的调用来实现。出于性能原因(甚至是易于实现),实现the three-argument read() method instead 并根据该方法重新实现无参数read() 方法可能更容易。

【讨论】:

  • 根据文档,您还需要实现 available() 方法。
  • 先生。 Ed:它清楚地说“应该”。而且由于您不应该依赖available() 来知道要准备多少字节,所以我会说流在默认实现下可以正常工作。
  • available() 的默认实现返回零。如果某个函数依赖它来知道他们是否可以读取和获取某些东西,那么除非 available() 有效,否则该函数将无法工作。
  • @Mr Ed:是的,这是真的。但是这样的功能会被破坏:available() 仅被定义为估计值。在我看来,依赖估计是准确的是错误的。
  • 最新的文档说:“...... InputStream 类的可用方法总是返回 0。这个方法应该被子类覆盖。返回:可以读取的字节数的估计(或跳过)从此输入流中无阻塞或到达输入流末尾时为 0。”无论如何,我首先提到它的唯一原因是因为我没有定义那个方法,所以我的程序没有工作。
【解决方案2】:

我在实现 InputStream 时遇到的一些非常重要的点。

  1. 覆盖可用()。正如 Javadoc 所说:

    InputStream 类的可用方法总是返回 0。 这个方法应该被子类覆盖。

    不覆盖此方法将导致任何尝试测试此流是否可读返回 false。例如,如果您将 inputStream 提供给 inputStreamReader,当您调用 reader.ready() 时,此阅读器将始终返回 false

  2. read() 中返回 -1。文档没有强调它:

    如果由于到达流的末尾而没有可用的字节,则返回值 -1。此方法会一直阻塞,直到输入数据可用、检测到流结束或引发异常。

    如果您选择在没有可用数据时阻止read(),则在某些情况下您必须记住return -1。不这样做可能会导致另一个read(byte b[], int off, int len) 阻止源中的以下代码:

    for (; i < len ; i++) {// default len is a relative large number (8192 - readPosition)
        c = read();
        if (c == -1) {
            break;
        }
        b[off + i] = (byte)c;
    }
    

    这会导致一些(如果不是全部)高级读取块,例如读者的readLine(), read() 等。

【讨论】:

    【解决方案3】:

    对于可能较大的数据,您可以使用来自guavacom.google.common.io.FileBackedOutputStream

    Javadoc:一个 OutputStream,它开始缓冲到一个字节数组,但一旦数据达到可配置的大小,就会切换到文件缓冲。

    使用out.getSupplier().getInput(),您可以获得您的 InputStream。

    【讨论】:

    • 我可以先将其用作输出流,提交所有数据,然后获取输入流,将所有数据提供给我的 FTP 客户端吗?
    • 是的,不是的,它应该比在飞行中做更容易。如果读取时出现任何错误,则不会发送任何内容。如果需要,您可以在调试时显示全部内容。这取决于你。
    【解决方案4】:

    完全没有必要创建自定义InputStream。使用ByteArrayInputStream,类似这样:

    public static InputStream createStream(){
        final String csv = createCsvFromDataBaseValues();
        return new ByteArrayInputStream(csv.getBytes());
    }
    

    特别是给出这句话:

    我的想法是加载所有数据 构造函数,然后覆盖读取 方法。

    如果您这样做,则通过实现自定义InputStream 将一无所获。它几乎等同于我上面概述的方法。

    【讨论】:

    • 它可能在数以万计的Application对象中;每个在 CSV 文件中生成大约 100 个字符的行。在内存中生成这么长的字符串是个好主意,还是制作一个临时文件并在完成后传输它会更好?
    • @John 无论哪种方式,我都会创建一个传递给 Application 对象的通用接口,并且我会尝试使用此接口的 StringBuilder- 和 File 支持的版本.
    【解决方案5】:

    为什么需要自定义输入流?为什么不直接将生成的 csv 数据写入正在写入 ftp 服务器的输出流?

    【讨论】:

    • 如果您可以将读写分区到separate threads,这是一个不错的方法。
    • @nobar,这很少有用。唯一有用的事情是生产者和消费者都可以任意阻止其他一些资源。
    【解决方案6】:

    如果数据不是太大,你可以:

    • 阅读全文
    • 转换为 CSV(文本)
    • 获取文本字节(通过String.getBytes(encoding)
    • 但是ByteArrayInputStream中的字节数组

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      • 2014-10-14
      • 2011-06-04
      相关资源
      最近更新 更多