views:

233

answers:

3

I understand how to fetch a URL text page and loop over the results

URL url = new URL(this.url);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
while ((line = reader.readLine()) != null) {
    ....

How would I do this to fetch an image and store it as a Blob?

A: 

For an image, instead of reading the buffer line by line, you'll load it in byte array, and save this byte array as a blob.

Riduidel
That's also possible, it's only possibly more memory hogging than using `InputStream`.
BalusC
+1  A: 

Just get it straight as InputStream and use PreparedStatement#setBinaryStream() to store it. It's binary data, not character data, so a Reader would only messup things, you don't want to have that.

In a nutshell:

InputStream input = imageUrl.openStream();

// ...

statement = connection.prepareStatement("INSERT INTO image (content) VALUES (?)");
statement.setBinaryStream(1, input);
statement.executeUpdate();

A PreparedStatement is really useful. It not only saves you from SQL injections, but it also eases setting fullworthy Java objects like InputStream in a SQL statement. You can learn more about PreparedStatement at the JDBC tutorial.

BalusC
Thanks, I'm making more progress with the InputStream, however, since I am using Google App Engine, I need to store the Blob to a property in an object. Could you clarify how I might convert the InputStream to a Blob?
Lloyd
Why would you ? Just use `PreparedStatement#setBinaryStream()` to store `InputStream` into a DB blob field and use `ResultSet#getBinaryStream()` to retrieve `InputStream` from a DB blob field. No need to hassle with `java.sql.Blob` or something tight-coupled like that in Java code.
BalusC
Thanks for your help, the little piece I was missing was to byte[] theBytes = new byte[input.available()];input.read(theBytes);
Lloyd
Trouble!! 1) Don't store it as `byte[]`, it's memory hogging, just stick to `InputStream`. 2) Don't use `input.available()`, it's just returns the next amount bytes available for read without blocking the stream, it doesn't denote the full content length (but which may **by coincidence** do so in case of smaller files).
BalusC
Thanks for the advice. I abandoned this train of thought soon afterwards, but I will keep your tips handy for the next time.
Lloyd
@BalusC I'm trying to follow your code but `setBinaryStream(1, input)` has one more int parameter for file size. How do you get around that?
mlevit
@mlevit: this parameter is optional.
BalusC
+1  A: 

Well what I do to store binary data such as images, is quite simplictic. In my case I deal with uploaded files which get posted to a servlet. Inside the servlet, I get the InputStream on the posted body with request.getInputStream(). However, this works with any kind of InputStreawm, inlcuding one based on an URL. The sample code below shows how to convert that InputStream into google appeninge Blob, which then you can for instance make persistant in the data store.

...
import org.apache.commons.io.IOUtils;
import com.google.appengine.api.datastore.Blob;
...

public void InputStreamToBlob(InputStream i) throws IOException {

    ...

    Blob content = new Blob(IOUtils.toByteArray(i));
    ...
Daniel