Built-in db4o Blob type helps you to get rid of the problems of byte[] array, though it has its own drawbacks. Pros and Cons for the points, mentioned above:
+ main database file stays a lot smaller
+ backups are possible over individual files
+ the BLOBs are accessible without db4o
- multiple files need to be managed
+ asynchronous storage allows the main application thread to continue its work, while blobs are being stored
- it is more difficult to move objects between db4o database files
+ big objects won't be loaded into memory as part of the activation process
Let's look, how it works.
First, BLOB storage should be defined:
Java: Db4o.configure().setBlobPath(storageFolder);
[/filter]
where storageFolder is a String value representing local or server path to store BLOBs. If that value is not defined, db4o will use the default folder "blobs" in user directory.
We will use a modified Car class, which holds reference to the car photo:
01/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */ 02
package com.db4odoc.blobs; 03
04
public class Car { 05
private String model; 06
private CarImage img; 07
08
09
public Car(String model) { 10
this.model=model; 11
img=new CarImage(); 12
img.setFile(model+".jpg"); 13
} 14
15
public CarImage getImage() { 16
return img; 17
} 18
19
public String toString() { 20
return model +"(" + img.getFile() + ")" ; 21
} 22
}
[filter=vb]VB: IBlob.ReadFrom( File )
As reading is done in a dedicated thread, you can use Blob#getStatus() in a loop to create a progress window.
The same applies to the write operation, which copies BLOB, stored with db4o, to the specified filesystem location.
Let's store some cars together with their images in our database:
01private static void storeCars() { 02
new File(DB4O_FILE_NAME).delete(); 03
ObjectContainer container=Db4o.openFile(DB4O_FILE_NAME); 04
try { 05
Car car1=new Car("Ferrari"); 06
container.set(car1); 07
storeImage(car1); 08
Car car2=new Car("BMW"); 09
container.set(car2); 10
storeImage(car2); 11
} finally { 12
container.close(); 13
} 14
}
CarImage is stored in the database just like normal object, no BLOB data is transferred before explicit call (Blob#readFrom in CarImage#readFile method), which copies the images to the storageFolder.
Please, note, that CarImage reference should be set to the database before uploading actual data. To get the images back to the filesystem we can run a usual query:
01private static void retrieveCars() { 02
ObjectContainer container=Db4o.openFile(DB4O_FILE_NAME); 03
try { 04
Query query = container.query(); 05
query.constrain(Car.class); 06
ObjectSet result = query.execute(); 07
getImages(result); 08
} finally { 09
container.close(); 10
} 11
}
and get BLOB data using retrieved Car references:
01private static void getImages(ObjectSet result){ 02
while(result.hasNext()) { 03
Car car = (Car)(result.next()); 04
System.out.println(car); 05
CarImage img = car.getImage(); 06
try { 07
img.writeFile(); 08
} catch (java.io.IOException ex){ 09
System.out.print(ex.getMessage()); 10
} 11
} 12
}
Retrieved images are placed in CarImage.outFolder ("blobs\out").
So query interface operates on references - no BLOB data is loaded into memory until explicit call (Blob#writeTo). This also means, that activationDepth does not affect Blob objects and best querying performance is achieved without additional coding.