如何使用具有自定义文件扩展名的 H2 数据库?

Posted

技术标签:

【中文标题】如何使用具有自定义文件扩展名的 H2 数据库?【英文标题】:How to use H2 databases with a custom file extension? 【发布时间】:2015-03-09 10:30:18 【问题描述】:

我正在构建一个将其数据存储在 H2 数据库文件中的应用程序,因此我的保存文件具有扩展名 .h2.db

打开应用程序时,用户必须选择应加载的保存文件。为了更容易识别这些文件,是否可以告诉 H2 使用自定义文件扩展名?

看H2的Database URL overview,只能指定数据库名。我更喜欢像.save 这样的扩展而不是默认的.h2.db。有没有合理的方法来实现这一点?

解决方法是将*.save-文件链接到一个临时文件夹,将其重命名为正确的后缀。如果这是唯一的解决方案,我想我会使用默认扩展名。

【问题讨论】:

我会说你不能使用不同的后缀。查看Database File Layout 和以下章节“移动和重命名数据库文件”。它声明[renaming is possible] as long as all files of the same database start with the same name and the respective extensions are unchanged 至少使用 FileNameExtensionFilter,并带有描述“保存文件 (*.h2.db)”。 【参考方案1】:

H2 数据库支持可插拔文件系统,因此您可以使用一些额外的代码来使用任何您想要的扩展。您只需要创建一个包装器,注册它并使用您自己的数据库 URL。包装器可能如下所示:

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;
  

然后你需要注册它:

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

并像这样使用数据库 URL:

"jdbc:h2:save:./mydatabase"

注意“save:”前缀,它应该匹配 getScheme() 方法返回的字符串。我在这里放了更多细节:http://shuvikov.net/blog/renaming-h2-database-files

【讨论】:

就我而言,我必须在 URL 中包含 ;MV_STORE=FALSE;MVCC=FALSE。喜欢jdbc:h2:save:./test;MV_STORE=FALSE;MVCC=FALSE【参考方案2】:

您不能为 H2 数据库名称(页面文件)定义新的扩展名(后缀)

在我的代码中我有类似的需求(用户可以选择数据库),这就是我所做的:

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, "");
    ...

注意:FileImport 是我编写的扩展 SWT FileDialog 的类:https://code.google.com/p/marcolopes/source/browse/org.dma.eclipse/src/org/dma/eclipse/swt/dialogs/file/FileImport.java

【讨论】:

【参考方案3】:

文件扩展名(注意有很多,不仅仅是.h2.db)在Constants.java中设置:

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

并直接在整个代码库中使用,例如在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);

所以不,您不能为数据库指定自定义文件扩展名。您最好不要担心这一点,或者像 JoopEggen 建议的那样使用 FileNameExtensionFilter 来限制用户的选择。

您可以压缩数据库文件并将.zip 重命名为其他扩展名,例如.save。然后您解压缩您的.save 文件以获取.h2.db 文件。请注意,这就是 Jars 的工作方式 - 它们只是隐藏的 zip 文件。

您也可以查看Game Developer Stack Exchange,并考虑在此处发布诸如“我如何创建用户友好的保存文件”之类的问题,如果您真的不能期望您的用户容忍.h2.db 文件,请描述您的问题.

【讨论】:

以上是关于如何使用具有自定义文件扩展名的 H2 数据库?的主要内容,如果未能解决你的问题,请参考以下文章

如何在文档目录中创建具有自定义扩展名的文件?

使用具有自定义扩展名的 SDF 文件(SQLCE 数据库)作为我的 WPF 应用程序的数据文件类型

Richfilemanager 列出具有自定义扩展名的文件

如何强制具有自定义扩展名的文本文件在 myApp 中打开,而不是在 Safari 中显示为文本

保存具有自定义扩展名的文件

如何将具有不同扩展名的文件作为BAT文件运行[重复]