提交 7beb10a8 authored 作者: Thomas Mueller's avatar Thomas Mueller

File systems with a maximum file size (for example FAT) are now supported.

上级 adf661ad
...@@ -68,4 +68,10 @@ public interface FileObject { ...@@ -68,4 +68,10 @@ public interface FileObject {
*/ */
void setFileLength(long newLength) throws IOException; void setFileLength(long newLength) throws IOException;
/**
* Get the full qualified name of this file.
*
* @return the name
*/
String getName();
} }
...@@ -84,5 +84,9 @@ public class FileObjectDatabase implements FileObject { ...@@ -84,5 +84,9 @@ public class FileObjectDatabase implements FileObject {
length = Math.max(length, pos); length = Math.max(length, pos);
changed = true; changed = true;
} }
public String getName() {
return fileName;
}
} }
...@@ -16,9 +16,12 @@ import org.h2.util.FileUtils; ...@@ -16,9 +16,12 @@ import org.h2.util.FileUtils;
* This class is extends a java.io.RandomAccessFile. * This class is extends a java.io.RandomAccessFile.
*/ */
public class FileObjectDisk extends RandomAccessFile implements FileObject { public class FileObjectDisk extends RandomAccessFile implements FileObject {
private final String name;
public FileObjectDisk(String fileName, String mode) throws FileNotFoundException { FileObjectDisk(String fileName, String mode) throws FileNotFoundException {
super(fileName, mode); super(fileName, mode);
this.name = fileName;
} }
public void sync() throws IOException { public void sync() throws IOException {
...@@ -29,4 +32,8 @@ public class FileObjectDisk extends RandomAccessFile implements FileObject { ...@@ -29,4 +32,8 @@ public class FileObjectDisk extends RandomAccessFile implements FileObject {
FileUtils.setLength(this, newLength); FileUtils.setLength(this, newLength);
} }
public String getName() {
return name;
}
} }
...@@ -89,7 +89,7 @@ public class FileObjectMemory implements FileObject { ...@@ -89,7 +89,7 @@ public class FileObjectMemory implements FileObject {
} }
//## Java 1.4 end ## //## Java 1.4 end ##
public FileObjectMemory(String name, boolean compress) { FileObjectMemory(String name, boolean compress) {
this.name = name; this.name = name;
this.compress = compress; this.compress = compress;
data = new byte[0][]; data = new byte[0][];
......
/*
* Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.store.fs;
import java.io.IOException;
import java.sql.SQLException;
import org.h2.message.Message;
import org.h2.util.FileUtils;
/**
* A file that may be split into multiple smaller files.
*/
public class FileObjectSplit implements FileObject {
private final String name;
private final String mode;
private final long maxLength;
private FileObject[] list;
private long filePointer;
private long length;
FileObjectSplit(String name, String mode, FileObject[] list, long length, long maxLength) {
this.name = name;
this.mode = mode;
this.list = list;
this.length = length;
this.maxLength = maxLength;
}
public void close() throws IOException {
for (int i = 0; i < list.length; i++) {
list[i].close();
}
}
public long getFilePointer() throws IOException {
return filePointer;
}
public long length() throws IOException {
return length;
}
private int read(byte[] b, int off, int len) throws IOException {
long offset = filePointer % maxLength;
int l = (int) Math.min(len, maxLength - offset);
FileObject fo = getFileObject();
fo.seek(offset);
fo.readFully(b, off, l);
filePointer += l;
return l;
}
public void readFully(byte[] b, int off, int len) throws IOException {
while (true) {
int l = read(b, off, len);
len -= l;
if (len <= 0) {
return;
}
off += l;
}
}
public void seek(long pos) throws IOException {
filePointer = pos;
}
private FileObject getFileObject() throws IOException {
int id = (int) (filePointer / maxLength);
while (id >= list.length) {
int i = list.length;
FileObject[] newList = new FileObject[i + 1];
System.arraycopy(list, 0, newList, 0, i);
String fileName = FileSystemSplit.getFileName(name, i);
newList[i] = FileSystem.getInstance(fileName).openFileObject(fileName, mode);
list = newList;
}
return list[id];
}
public void setFileLength(long newLength) throws IOException {
filePointer = Math.min(filePointer, newLength);
int newFileCount = 1 + (int) (newLength / maxLength);
if (newFileCount == list.length) {
long size = newLength - maxLength * (newFileCount - 1);
list[list.length - 1].setFileLength(size);
} else {
FileObject[] newList = new FileObject[newFileCount];
int max = Math.max(newFileCount, list.length);
long remaining = newLength;
for (int i = 0; i < max; i++) {
long size = Math.min(remaining, maxLength);
remaining -= size;
if (i >= newFileCount) {
list[i].close();
try {
FileUtils.delete(list[i].getName());
} catch (SQLException e) {
throw Message.convertToIOException(e);
}
} else if (i >= list.length) {
String fileName = FileSystemSplit.getFileName(name, i);
FileObject o = FileSystem.getInstance(fileName).openFileObject(fileName, mode);
o.setFileLength(size);
newList[i] = o;
} else {
FileObject o = list[i];
if (o.length() != size) {
o.setFileLength(size);
}
newList[i] = list[i];
}
}
list = newList;
}
this.length = newLength;
}
public void sync() throws IOException {
for (int i = 0; i < list.length; i++) {
list[i].sync();
}
}
public void write(byte[] b, int off, int len) throws IOException {
while (true) {
int l = writePart(b, off, len);
len -= l;
if (len <= 0) {
return;
}
off += l;
}
}
private int writePart(byte[] b, int off, int len) throws IOException {
long offset = filePointer % maxLength;
int l = (int) Math.min(len, maxLength - offset);
FileObject fo = getFileObject();
fo.seek(offset);
fo.write(b, off, l);
filePointer += l;
length = Math.max(length, filePointer);
return l;
}
public String getName() {
return name;
}
}
...@@ -28,7 +28,7 @@ public class FileObjectZip implements FileObject { ...@@ -28,7 +28,7 @@ public class FileObjectZip implements FileObject {
private long inPos; private long inPos;
private long length; private long length;
public FileObjectZip(ZipFile file, ZipEntry entry) { FileObjectZip(ZipFile file, ZipEntry entry) {
this.file = file; this.file = file;
this.entry = entry; this.entry = entry;
length = entry.getSize(); length = entry.getSize();
...@@ -85,4 +85,8 @@ public class FileObjectZip implements FileObject { ...@@ -85,4 +85,8 @@ public class FileObjectZip implements FileObject {
throw new IOException("File is read-only"); throw new IOException("File is read-only");
} }
public String getName() {
return file.getName();
}
} }
...@@ -36,6 +36,12 @@ public abstract class FileSystem { ...@@ -36,6 +36,12 @@ public abstract class FileSystem {
*/ */
public static final String PREFIX_ZIP = "zip:"; public static final String PREFIX_ZIP = "zip:";
/**
* The prefix used to split large files (required for a FAT32 because it
* only support files up to 2 GB).
*/
public static final String PREFIX_SPLIT = "split:";
/** /**
* Get the file system object. * Get the file system object.
* *
...@@ -49,6 +55,8 @@ public abstract class FileSystem { ...@@ -49,6 +55,8 @@ public abstract class FileSystem {
return FileSystemDatabase.getInstance(fileName); return FileSystemDatabase.getInstance(fileName);
} else if (fileName.startsWith(PREFIX_ZIP)) { } else if (fileName.startsWith(PREFIX_ZIP)) {
return FileSystemZip.getInstance(); return FileSystemZip.getInstance();
} else if (fileName.startsWith(PREFIX_SPLIT)) {
return FileSystemSplit.getInstance();
} }
return FileSystemDisk.getInstance(); return FileSystemDisk.getInstance();
} }
......
...@@ -39,6 +39,9 @@ public class TestFileSystem extends TestBase { ...@@ -39,6 +39,9 @@ public class TestFileSystem extends TestBase {
public void test() throws Exception { public void test() throws Exception {
testDatabaseInMemFileSys(); testDatabaseInMemFileSys();
testDatabaseInJar(); testDatabaseInJar();
// set default part size to 1 << 10
FileSystem.getInstance(FileSystem.PREFIX_SPLIT + "10:" + baseDir + "/fs");
testFileSystem(FileSystem.PREFIX_SPLIT + baseDir + "/fs");
testFileSystem(baseDir + "/fs"); testFileSystem(baseDir + "/fs");
testFileSystem(FileSystem.PREFIX_MEMORY); testFileSystem(FileSystem.PREFIX_MEMORY);
// testFileSystem("jdbc:h2:mem:fs;TRACE_LEVEL_FILE=3"); // testFileSystem("jdbc:h2:mem:fs;TRACE_LEVEL_FILE=3");
...@@ -177,8 +180,8 @@ public class TestFileSystem extends TestBase { ...@@ -177,8 +180,8 @@ public class TestFileSystem extends TestBase {
fs.createDirs(fsBase + "/testDir/test"); fs.createDirs(fsBase + "/testDir/test");
assertTrue(fs.isDirectory(fsBase + "/testDir")); assertTrue(fs.isDirectory(fsBase + "/testDir"));
if (!fsBase.startsWith(FileSystem.PREFIX_DB)) { if (!fsBase.startsWith(FileSystem.PREFIX_DB)) {
fs.deleteRecursive("/testDir"); fs.deleteRecursive(fsBase + "/testDir");
assertTrue(!fs.exists("/testDir")); assertTrue(!fs.exists(fsBase + "/testDir"));
} }
} }
fs.close(); fs.close();
...@@ -234,20 +237,20 @@ public class TestFileSystem extends TestBase { ...@@ -234,20 +237,20 @@ public class TestFileSystem extends TestBase {
len = (int) Math.min(len, ra.length() - ra.getFilePointer()); len = (int) Math.min(len, ra.length() - ra.getFilePointer());
byte[] b1 = new byte[len]; byte[] b1 = new byte[len];
byte[] b2 = new byte[len]; byte[] b2 = new byte[len];
f.readFully(b1, 0, len); ra.readFully(b1, 0, len);
ra.readFully(b2, 0, len); f.readFully(b2, 0, len);
trace("readFully " + len); trace("readFully " + len);
assertEquals(b1, b2); assertEquals(b1, b2);
break; break;
} }
case 4: { case 4: {
trace("getFilePointer"); trace("getFilePointer");
assertEquals(f.getFilePointer(), ra.getFilePointer()); assertEquals(ra.getFilePointer(), f.getFilePointer());
break; break;
} }
case 5: { case 5: {
trace("length " + ra.length()); trace("length " + ra.length());
assertEquals(f.length(), ra.length()); assertEquals(ra.length(), f.length());
break; break;
} }
case 6: { case 6: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论