stuXnet
stuXnet

Reputation: 4349

How to use H2 databases with a custom file extension?

I'm building an application which stores its data in H2 database files, so my save files have the extension .h2.db.

When opening the application, the user has to select which save file should be loaded. To make it easier to recognize these files, is it possible to tell H2 to use custom file extensions?

Looking at the Database URL overview of H2, I can only specify the name of the database. I would prefer a extension like .save over the default .h2.db. Is there a reasonable way to achieve this?

A workaround would be to link the *.save-file to a temporary folder, renaming it to the correct suffix. If this is the only solution, I guess I would go with the default extension.

Upvotes: 4

Views: 5200

Answers (3)

dimo414
dimo414

Reputation: 48794

The filename extensions (notice there are many, not just .h2.db) are set in Constants.java:

/**
 * The file name suffix of page files.
 */
public static final String SUFFIX_PAGE_FILE = ".h2.db";

And used directly throughout the codebase, e.g. in Database.java:

/**
 * Check if a database with the given name exists.
 *
 * @param name the name of the database (including path)
 * @return true if one exists
 */
static boolean exists(String name) {
    if (FileUtils.exists(name + Constants.SUFFIX_PAGE_FILE)) {
        return true;
    }
    return FileUtils.exists(name + Constants.SUFFIX_MV_FILE);
}

So no, you cannot specify a custom file extension for the database. You'll be much better off either not worrying about this, or using a FileNameExtensionFilter to limit your user's choices, like JoopEggen suggested.

You could zip up your database files and rename the .zip to some other extension like .save. Then you unzip your .save file in order to get to the .h2.db file. Note this is how Jars work - they're just zip files under the covers.

You might also look at the Game Developer Stack Exchange, and consider posting a question there like "How do I create user-friendly save files" and describe your problem if you really can't expect your users to tolerate .h2.db files.

Upvotes: 0

Andrey
Andrey

Reputation: 114

H2 database supports pluggable file system so with a bit of extra code you can use any extension you want. You just need to create a wrapper, register it and use your own database URL. The wrapper could look like this:

package my.test;

import org.h2.store.fs.FilePath;
import org.h2.store.fs.FilePathWrapper;

public class FilePathTestWrapper extends FilePathWrapper {
  private static final String[][] MAPPING = {
    {".h2.db", ".save"}, 
    {".lock.db", ".save.lock"}
  };

  @Override
  public String getScheme() {
    return "save";
  }

  @Override
  public FilePathWrapper wrap(FilePath base) {
    // base.toString() returns base.name
    FilePathTestWrapper wrapper = (FilePathTestWrapper) super.wrap(base);
    wrapper.name = getPrefix() + wrapExtension(base.toString());
    return wrapper;
  }

  @Override
  protected FilePath unwrap(String path) {
    String newName = path.substring(getScheme().length() + 1);
    newName = unwrapExtension(newName);
    return FilePath.get(newName);
  }

  protected static String wrapExtension(String fileName) {
    for (String[] pair : MAPPING) {
      if (fileName.endsWith(pair[1])) {
        fileName = fileName.substring(0, fileName.length() - pair[1].length()) + pair[0];
        break;
      }
    }
    return fileName;
  }

  protected static String unwrapExtension(String fileName) {
    for (String[] pair : MAPPING) {
      if (fileName.endsWith(pair[0])) {
        fileName = fileName.substring(0, fileName.length() - pair[0].length()) + pair[1];
        break;
      }
    }
    return fileName;
  }
}

Then you'll need to register it:

FilePathTestWrapper wrapper = new FilePathTestWrapper();
FilePath.register(wrapper);

And use database URL like this:

"jdbc:h2:save:./mydatabase"

Note the "save:" prefix, it should match string returned by getScheme() method. I put a bit more details here: http://shuvikov.net/blog/renaming-h2-database-files

Upvotes: 5

marcolopes
marcolopes

Reputation: 9287

You cannot define a new extension (suffix) for the H2 database name (page file)

In my code i have a similar need (user may select the database) and this is what i do:

File file=new FileImport(shell, "*"+org.h2.engine.Constants.SUFFIX_PAGE_FILE).filePicker();
if (file!=null){
    String database=file.getAbsolutePath().
            replace(org.h2.engine.Constants.SUFFIX_PAGE_FILE, "");
    ...
}

NOTE: FileImport is a class writen by me that extends SWT FileDialog: https://code.google.com/p/marcolopes/source/browse/org.dma.eclipse/src/org/dma/eclipse/swt/dialogs/file/FileImport.java

Upvotes: 0

Related Questions