Java中的简单流读写问题

4
我正在尝试通过URLConnection上传文件,但我需要将其作为二进制文件读取/写入,而不进行任何编码更改。
因此,我尝试从FileInputStream中读取byte[]数组,但现在我有一个问题。我用于向服务器输出的PrintWriter对象不允许我执行writer.write(content)(其中content是byte[]类型)。我该如何解决这个问题?或者是否有另一种快速将二进制数据从FileInputStream复制到PrintWriter的方法?
谢谢
4个回答

6
我敢打赌这是对这个问题的跟进:将文件从Java客户端上传到HTTP服务器 如果您想同时使用multipart/form-data上传二进制文件,则需要将它们写入OutputStream。这是代码示例的更改版本,只修改了try块以保留二进制输出流的单独句柄,这样您就可以将任何InputStream写入其中,而不需要进行任何编码操作:
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是否与操作系统有关(不同的endlines适用于不同的操作系统)?HTTP是否需要\r\n行结尾?就我测试的情况而言,它并不是很在意,但仍然...做正确会更好。当我有足够的时间时,我会查看你在另一篇帖子中给我的RFC链接。 - Marius
这只是一个启动示例 :) 我们不会用100个类/方法以及完整的文档等体面的OO方式编写整个程序,或者说 ;) 那是你的工作。实际上,\r\n 被指定为行分隔符。你可以自己处理它,或者通过 -Dline.separator=0xA0xD 或其他方式配置系统默认行分隔符。 - BalusC
是的,我知道,这足够清晰,可以制作一个不错的面向对象的东西;] 感谢您的帮助;] - Marius

2
Writer对象(包括PrintWriter)专门用于输出字符数据。看起来你想在这里使用一个OutputStream而不是一个Writer
你的PrintWriter是从哪里来的?如果它是通过将某种类型的OutputStreamOutputStreamWriter包装,然后再将其包装为PrintWriter创建的,则应该只使用原始OutputStream的原始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()非常方便。 - Marius
PrintWriter来自于: writer = new PrintWriter(new OutputStreamWriter(this.conn.getOutputStream(), "UTF-8")); - Marius
println()确实很方便,但不幸的是,它只能用于编码字符数据。如果您想要推送未编码的字节,则需要使用write()而不是println() - Joe Carnahan
有没有办法将UTF-8编码的字符串传递给write(),例如将其转换为byte[]或类似的东西?这将使我能够使用write()写入文本数据并解决byte[]数组的问题。 - Marius
看到我的编辑答案 - 我已经在解决这个问题了。 :-) - Joe Carnahan
显示剩余2条评论

2
你可以在URLConnection上使用“getOutputStream()”。PrintWriter是从哪里来的?

PrintWriter来自: writer = new PrintWriter(new OutputStreamWriter(this.conn.getOutputStream(), "UTF-8")); - Marius
1
@Marius:Writer 用于文本数据,对于二进制数据仅使用 OutputSteam(Reader/InputStream 同理)。你难道没有想过为什么在只想传输二进制数据时还需要提供编码("UTF-8")吗? - Joachim Sauer
@Joachim Sauer:是的,我确实这样做了,这就是为什么我来到这个论坛寻找解决方案的原因,因为Sun的文档说明写入器并不是我所需要的 :) 无论如何,问题现在已经解决,感谢大家的帮助。 - Marius

1

您不应该使用PrintWriter,因为它是为文本表示而设计的,而您需要二进制。一个普通的OutputStream应该就可以了,因为所有的Writer都是基于字符的,本质上是文本。

您想要实现什么目标?


@Marius,你实际上需要一个同时具有编码二进制数据(文本)和未编码二进制数据的流。接收方必须找出哪个是哪个。在我看来,你应该改变你的模型并使用消息,例如使用XML实现,其中包含一个结构化文本部分和一个用于二进制内容的cdata部分。 - extraneon
@Marius 或者当然可以使用 HTTP,在头部发送一些文本,以及将二进制数据作为内容发送,如果这种模式更加适合。 - extraneon
@extraneon:接收器不是问题。XML不是一个选项,因为我需要一个符合HTTP协议的POST请求,让任何Web服务器都可以处理。问题在于如何将数据写入其中。难道没有一种方式可以将字符和二进制数据输出到同一个输出流中吗? - Marius
@extraneon 或许我可以使用某种二进制流,并使用某种将字符串转换为byte[]的方法将字符数据写入其中?这样,我就可以轻松地将文本和二进制数据写入同一流中。 - Marius
只要接收者理解格式并知道如何解码,那当然可以。 - extraneon
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接