19 březen 2013

Google App Engine has sort of support for saving files to the blobstore. Gaelyk adds some nice sugar to the files service. You can easily create file in blobstore using following shortcut:

Creating file in the blobstore

def file = files.createNewBlobFile("text/plain", "hello.txt")

file.withWriter { writer ->
    writer << "some content"
}

It is very nice that you have to set the content type and the name of the file but neither the content type nor the file
name is used anywhere. If you serve the file from the blobstore
the content type doesn't seem to be set to the response and of course you can't find file by its name easily. But it doesn't mean there
is no way how to do it.

Google offers class BlobInfoFactory
to query the information about stored blobs but you would have to walk throught all the blobs in your application to find the proper blob.
Luckily, blob information is just plain entity and
BlobInfoFactory
exposes fields BlobInfoFactory.KIND, BlobInfoFactory.CREATION and BlobInfoFactory.FILENAME which can help you find the desired file.

String name = "hello.txt"
def files = datastore.execute {
    from BlobInfoFactory.KIND
    where BlobInfoFactory.FILENAME == name
    sort desc by BlobInfoFactory.CREATION
}
if(files){
    new BlobKey(files[0].key.name).serve(response)
} else {
    response.status = 404
    out << "No such file $name"
}

Since the file name isn't guaranteed to be unique, you can get more than one result. Sorting the blob information by its creation time
help you to get the latest file as the first element of returned list. This might be acctually handy if you want to implement very simple and
inefficient version system. You can create new blob key from the name of the entity returned from the query and using this key you can serve
the file to the client.