提交 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 {
*/
void setFileLength(long newLength) throws IOException;
/**
* Get the full qualified name of this file.
*
* @return the name
*/
String getName();
}
......@@ -85,4 +85,8 @@ public class FileObjectDatabase implements FileObject {
changed = true;
}
public String getName() {
return fileName;
}
}
......@@ -17,8 +17,11 @@ import org.h2.util.FileUtils;
*/
public class FileObjectDisk extends RandomAccessFile implements FileObject {
public FileObjectDisk(String fileName, String mode) throws FileNotFoundException {
private final String name;
FileObjectDisk(String fileName, String mode) throws FileNotFoundException {
super(fileName, mode);
this.name = fileName;
}
public void sync() throws IOException {
......@@ -29,4 +32,8 @@ public class FileObjectDisk extends RandomAccessFile implements FileObject {
FileUtils.setLength(this, newLength);
}
public String getName() {
return name;
}
}
......@@ -89,7 +89,7 @@ public class FileObjectMemory implements FileObject {
}
//## Java 1.4 end ##
public FileObjectMemory(String name, boolean compress) {
FileObjectMemory(String name, boolean compress) {
this.name = name;
this.compress = compress;
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 {
private long inPos;
private long length;
public FileObjectZip(ZipFile file, ZipEntry entry) {
FileObjectZip(ZipFile file, ZipEntry entry) {
this.file = file;
this.entry = entry;
length = entry.getSize();
......@@ -85,4 +85,8 @@ public class FileObjectZip implements FileObject {
throw new IOException("File is read-only");
}
public String getName() {
return file.getName();
}
}
......@@ -36,6 +36,12 @@ public abstract class FileSystem {
*/
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.
*
......@@ -49,6 +55,8 @@ public abstract class FileSystem {
return FileSystemDatabase.getInstance(fileName);
} else if (fileName.startsWith(PREFIX_ZIP)) {
return FileSystemZip.getInstance();
} else if (fileName.startsWith(PREFIX_SPLIT)) {
return FileSystemSplit.getInstance();
}
return FileSystemDisk.getInstance();
}
......
......@@ -39,6 +39,9 @@ public class TestFileSystem extends TestBase {
public void test() throws Exception {
testDatabaseInMemFileSys();
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(FileSystem.PREFIX_MEMORY);
// testFileSystem("jdbc:h2:mem:fs;TRACE_LEVEL_FILE=3");
......@@ -177,8 +180,8 @@ public class TestFileSystem extends TestBase {
fs.createDirs(fsBase + "/testDir/test");
assertTrue(fs.isDirectory(fsBase + "/testDir"));
if (!fsBase.startsWith(FileSystem.PREFIX_DB)) {
fs.deleteRecursive("/testDir");
assertTrue(!fs.exists("/testDir"));
fs.deleteRecursive(fsBase + "/testDir");
assertTrue(!fs.exists(fsBase + "/testDir"));
}
}
fs.close();
......@@ -234,20 +237,20 @@ public class TestFileSystem extends TestBase {
len = (int) Math.min(len, ra.length() - ra.getFilePointer());
byte[] b1 = new byte[len];
byte[] b2 = new byte[len];
f.readFully(b1, 0, len);
ra.readFully(b2, 0, len);
ra.readFully(b1, 0, len);
f.readFully(b2, 0, len);
trace("readFully " + len);
assertEquals(b1, b2);
break;
}
case 4: {
trace("getFilePointer");
assertEquals(f.getFilePointer(), ra.getFilePointer());
assertEquals(ra.getFilePointer(), f.getFilePointer());
break;
}
case 5: {
trace("length " + ra.length());
assertEquals(f.length(), ra.length());
assertEquals(ra.length(), f.length());
break;
}
case 6: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论