4

I'm trying to upload a file via URLConnection, but I need to read/write it as a binary file without any encoding changes.

So i've tried to read byte[] array from a FileInputStream, but now i have an issue. The PrintWriter object I use for outputing to the server does not allow me to do writer.write(content) (where content is of type byte[]). How can i fix this? Or is there another way to quickly copy binary data from a FileInputStream to a PrintWriter?

Thank you

4 Answers 4

6

I bet that this is an follow-up on this question: Upload files from Java client to a HTTP server

If you want to upload binary files as well using multipart/form-data, then you need to write them to the OutputStream instead. Here's the changed example of the code as I posted in your previous example, only the try block has been changed to keep a separate handle to the binary output stream, so that you can write any InputStreams to it without any encoding pains:

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();
}
Sign up to request clarification or add additional context in comments.

3 Comments

@BalusC: you're right :) I've managed to modify the code myself, although it looks different from yours now, since it's in a separate http connection class, allowing more control over what i need. By the way, isn't println os dependent (different endlines for different os'es)? And doesn't HTTP need \r\n line endings? As far as i've tested, it doesn't really care much, but still ... would be nice to do it correctly. I'll have a look through the RFC link you gave me in another post when i have enough time just in case.
It's just a kickoff example :) I am (we are) not going to program the whole thing in a decent OO way in 100 classes/methods complete with documentation and so on, or so ;) That's your job. And indeed, \r\n is specified as line separator. You can either take it in own hands or configure the system default line separator by -Dline.separator=0xA0xD or so.
Yes yes i know, and it's clear enough to make a decent OO thing out of it ;] Thanks for your help ;]
2

Writer objects (including PrintWriter) are intended specifically for output of character data. It sounds like you want an OutputStream instead of a Writer here.

Where did your PrintWriter come from? If it was created by wrapping some kind of OutputStream with an OutputStreamWriter and then wrapping that with a PrintWriter, then you should just use the original write(byte[] b) method from the original OutputStream, rather than trying to use a Writer.

If you want to mix character output and byte output, you may need to use String.getBytes(). Check out this example:

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);

(Of course, this will only work if the system that is reading your output understands that you are writing a mixture of characters and raw bytes and knows how to handle the mixed data that you are sending it.)

7 Comments

But how would i then output character data to OutputStream? Now it's very convenient to use println().
PrintWriter is comming from: writer = new PrintWriter(new OutputStreamWriter(this.conn.getOutputStream(), "UTF-8"));
println() is definitely convenient, but unfortunately, it only works with encoded character data. If you want to push unencoded bytes, then you need to use write() instead of println().
Is there any way to pass a UTF-8 encoded string to write(), eg. converting it to byte[] or something like that? That would enable me to write textual data with write() and solve the problem with byte[] array.
See my edited answer - I was already working on a solution to that. :-)
|
2

You could use 'getOutputStream()' on your URLConnection. Where is the PrintWriter coming from?

3 Comments

PrintWriter is comming from: writer = new PrintWriter(new OutputStreamWriter(this.conn.getOutputStream(), "UTF-8"));
@Marius: Writer are used for text data, for binary data use only OuputStream (the same is true for Reader/InputStream). Didn't you wonder why you had to provide an encoding ("UTF-8") when you only wanted to transfer binary data?
@Joachim Sauer: Yes i did, that's why i came to this forum to find a solution for this, since sun's documentation stated that witers were not what i needed :) Anyway, the question is now solved, thank you all for your help.
1

You should not use a PrintWriter as that is designed for text representation, and you want binary. A plain OutputStream should do, as Writers all operate on chars, in essence, text.

What do you want to achieve?

7 Comments

All Writers are for textual (character) output.
I want to have a stream i could write character and binary data into. Basically i'm constructing a HTTP request that has textual parameters (form data) and binary data (files)
@Marius You actually want a stream which has both encoded binary data (the text) and unencoded binary data. The receiver has to find out which is what. In my view you should change your model and use messages, for instance implemented with XML with a structured text section and a cdata section for binary stuff.
@Marius or of course use HTTP and send some text in headers, and binary data as content, if that model is more appropriate.
@extraneon: The receiver is not a problem. XML is not an option, because i need a HTTP protocol compliant POST request that any web server can process. The problem is writing the data to it. Isn't there any way to output character and binary data to the same output stream?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.