【问题标题】:Simple stream read/write question in javajava中的简单流读/写问题
【发布时间】:2010-03-19 13:04:19
【问题描述】:

我正在尝试通过 URLConnection 上传文件,但我需要将其作为二进制文件读取/写入,而无需更改任何编码。

所以我尝试从FileInputStream 中读取byte[] 数组,但现在我遇到了问题。我用于输出到服务器的PrintWriter 对象不允许我执行writer.write(content)(其中content 的类型为byte[])。我怎样才能解决这个问题?或者有没有其他方法可以快速将二进制数据从FileInputStream 复制到PrintWriter

谢谢

【问题讨论】:

    标签: java io


    【解决方案1】:

    我敢打赌,这是对这个问题的后续跟进:Upload files from Java client to a HTTP server

    如果您还想使用multipart/form-data 上传二进制文件,则需要将它们写入OutputStream。这是我在上一个示例中发布的代码的更改示例,仅更改了 try 块以保留二进制输出流的单独句柄,因此您可以在没有任何编码的情况下向其写入任何 InputStreams痛苦:

    OutputStream output = null;
    PrintWriter writer = null;
    try {
        output = connection.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true); // true = Autoflush, important!
    
        writer.println("--" + boundary);
        writer.println("Content-Disposition: form-data; name=\"paramToSend\"");
        writer.println("Content-Type: text/plain; charset=UTF-8");
        writer.println();
        writer.println(paramToSend);
    
        writer.println("--" + boundary);
        writer.println("Content-Disposition: form-data; name=\"fileToUpload\"; filename=\"" + fileToUpload.getName() + "\"");
        writer.println("Content-Type: " + URLConnection.guessContentTypeFromName(fileToUpload.getName());
        writer.println("Content-Transfer-Encoding: binary");
        writer.println();
        InputStream input = null;
        try {
            input = new FileInputStream(fileToUpload);
            byte[] buffer = new byte[1024];
            for (int length = 0; (length = input.read(buffer)) > 0;) {
                output.write(buffer, 0, length);
            }
            output.flush();
        } finally {
            if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
        }
        writer.println();
    
        writer.println("--" + boundary + "--");
    } finally {
        if (writer != null) writer.close();
    }
    

    【讨论】:

    • @BalusC: 你是对的 :) 我已经设法自己修改了代码,虽然它现在看起来与你的不同,因为它在一个单独的 http 连接类中,允许更多地控制我需要。顺便说一句,println 不是依赖于操作系统(不同操作系统的不同端线)吗? HTTP 不需要 \r\n 行尾吗?据我测试,它并不在乎,但仍然......正确地做到这一点会很好。当我有足够的时间以防万一时,我会看看你在另一篇文章中给我的 RFC 链接。
    • 只是一个启动示例 :) 我(我们)不会在 100 个包含文档的类/方法中以体面的 OO 方式对整个事物进行编程,等等上,或左右;)那是你的工作。事实上,\r\n 被指定为行分隔符。你可以自己动手,也可以通过-Dline.separator=0xA0xD左右配置系统默认的行分隔符。
    • 是的,我知道,而且很清楚,可以从中做出体面的 OO 事情;] 感谢您的帮助;]
    【解决方案2】:

    Writer 对象(包括PrintWriter)专门用于字符数据的输出。听起来你想要一个OutputStream 而不是这里的Writer

    您的PrintWriter 来自哪里?如果它是通过用OutputStreamWriter 包装某种OutputStream 然后用PrintWriter 包装来创建的,那么您应该只使用原始write(byte[] b) 中的原始write(byte[] b) 方法,而不是尝试使用Writer

    如果你想混合字符输出和字节输出,你可能需要使用String.getBytes()。看看这个例子:

    OutputStream o = this.conn.getOutputStream(); // Based on your comment
    String s = "Hello, world!";
    byte[] b = ...;      // These are the raw bytes that you want to write
    o.write(s.getBytes("UTF-8"));
    o.write(b);
    

    (当然,这只有在读取您的输出的系统知道您正在编写字符和原始字节的混合并且知道如何处理您发送的混合数据时才有效。)

    【讨论】:

    • 但是我如何将字符数据输出到 OutputStream?现在使用 println() 非常方便。
    • PrintWriter 来自:writer = new PrintWriter(new OutputStreamWriter(this.conn.getOutputStream(), "UTF-8"));
    • println() 绝对方便,但不幸的是,它只适用于编码的字符数据。如果要推送未编码的字节,则需要使用write() 而不是println()
    • 有什么方法可以将 UTF-8 编码的字符串传递给 write(),例如。将其转换为 byte[] 或类似的东西?这将使我能够使用 write() 写入文本数据并使用 byte[] 数组解决问题。
    • 查看我编辑的答案 - 我已经在研究解决方案。 :-)
    【解决方案3】:

    您可以在 URLConnection 上使用“getOutputStream()”。 PrintWriter 来自哪里?

    【讨论】:

    • PrintWriter 来自:writer = new PrintWriter(new OutputStreamWriter(this.conn.getOutputStream(), "UTF-8"));
    • @Marius:Writer 用于文本数据,二进制数据仅使用 OuputStream(Reader/InputStream 也是如此)。当您只想传输二进制数据时,您有没有想过为什么必须提供编码 ("UTF-8")?
    • @Joachim Sauer:是的,我做到了,这就是为什么我来这个论坛寻找解决方案的原因,因为 sun 的文档表明我不需要 witers :) 无论如何,现在问题已经解决了,谢谢大家的帮助。
    【解决方案4】:

    您不应该使用为 text 表示而设计的 PrintWriter,并且您需要二进制。一个普通的 OutputStream 应该这样做,因为 Writers 都对字符进行操作,本质上是文本。

    你想达到什么目的?

    【讨论】:

    • 所有 Writers 用于文本(字符)输出。
    • 我想要一个可以写入字符和二进制数据的流。基本上我正在构建一个具有文本参数(表单数据)和二进制数据(文件)的 HTTP 请求
    • @Marius 您实际上想要一个包含编码二进制数据(文本)和未编码二进制数据的流。接收者必须找出哪个是什么。在我看来,您应该更改模型并使用消息,例如使用带有结构化文本部分的 XML 和用于二进制内容的 cdata 部分来实现。
    • @Marius 或者当然使用 HTTP 并在标头中发送一些文本,并将二进制数据作为内容,如果该模型更合适的话。
    • @extraneon:接收器没有问题。 XML 不是一个选项,因为我需要任何 Web 服务器都可以处理的符合 HTTP 协议的 POST 请求。问题是将数据写入其中。有没有办法将字符和二进制数据输出到同一个输出流?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多