More efficient filesystem implementation

This commit is contained in:
Alexey Andreev 2019-09-05 17:11:43 +03:00
parent f47644d890
commit 5b739238c2
8 changed files with 109 additions and 105 deletions

View File

@ -18,9 +18,15 @@ package org.teavm.classlib.fs;
import java.io.IOException; import java.io.IOException;
public interface VirtualFileAccessor { public interface VirtualFileAccessor {
int read(int pos, byte[] buffer, int offset, int limit) throws IOException; int read(byte[] buffer, int offset, int limit) throws IOException;
void write(int pos, byte[] buffer, int offset, int limit) throws IOException; void write(byte[] buffer, int offset, int limit) throws IOException;
int tell() throws IOException;
void seek(int target) throws IOException;
void skip(int amount) throws IOException;
int size() throws IOException; int size() throws IOException;

View File

@ -100,7 +100,7 @@ public class CVirtualFile implements VirtualFile {
if (file == 0) { if (file == 0) {
return null; return null;
} }
return new CVirtualFileAccessor(file, append ? -1 : 0); return new CVirtualFileAccessor(file);
} }
@Override @Override

View File

@ -20,38 +20,50 @@ import org.teavm.classlib.fs.VirtualFileAccessor;
public class CVirtualFileAccessor implements VirtualFileAccessor { public class CVirtualFileAccessor implements VirtualFileAccessor {
private long file; private long file;
private int position;
public CVirtualFileAccessor(long file, int position) { public CVirtualFileAccessor(long file) {
this.file = file; this.file = file;
this.position = position;
} }
@Override @Override
public int read(int pos, byte[] buffer, int offset, int limit) throws IOException { public int read(byte[] buffer, int offset, int limit) throws IOException {
ensurePosition(pos); return CFileSystem.read(file, buffer, offset, limit);
int bytesRead = CFileSystem.read(file, buffer, offset, limit);
position += bytesRead;
return bytesRead;
} }
@Override @Override
public void write(int pos, byte[] buffer, int offset, int limit) throws IOException { public void write(byte[] buffer, int offset, int limit) throws IOException {
ensurePosition(pos);
int bytesWritten = CFileSystem.write(file, buffer, offset, limit); int bytesWritten = CFileSystem.write(file, buffer, offset, limit);
if (bytesWritten < limit) { if (bytesWritten < limit) {
throw new IOException(); throw new IOException();
} }
position += bytesWritten; }
@Override
public int tell() throws IOException {
return CFileSystem.tell(file);
}
@Override
public void skip(int amount) throws IOException {
CFileSystem.seek(file, 0, amount);
}
@Override
public void seek(int target) throws IOException {
CFileSystem.seek(file, 0, target);
} }
@Override @Override
public int size() throws IOException { public int size() throws IOException {
int current = CFileSystem.tell(file);
if (!CFileSystem.seek(file, 2, 0)) { if (!CFileSystem.seek(file, 2, 0)) {
throw new IOException(); throw new IOException();
} }
position = CFileSystem.tell(file); int result = CFileSystem.tell(file);
return position; if (!CFileSystem.seek(file, 0, current)) {
throw new IOException();
}
return result;
} }
@Override @Override
@ -59,11 +71,13 @@ public class CVirtualFileAccessor implements VirtualFileAccessor {
if (!CFileSystem.seek(file, 2, 0)) { if (!CFileSystem.seek(file, 2, 0)) {
throw new IOException(); throw new IOException();
} }
position = CFileSystem.tell(file); int position = CFileSystem.tell(file);
if (position < size) { if (position < size) {
byte[] zeros = new byte[4096]; byte[] zeros = new byte[4096];
while (position < size) { while (position < size) {
write(position, zeros, 0, Math.min(zeros.length, size - position)); int bytesToWrite = Math.min(zeros.length, size - position);
write(zeros, 0, bytesToWrite);
position += bytesToWrite;
} }
} }
} }
@ -83,13 +97,4 @@ public class CVirtualFileAccessor implements VirtualFileAccessor {
throw new IOException(); throw new IOException();
} }
} }
private void ensurePosition(int pos) throws IOException {
if (position != pos) {
if (!CFileSystem.seek(file, 0, pos)) {
throw new IOException();
}
position = pos;
}
}
} }

View File

@ -58,21 +58,50 @@ public class InMemoryVirtualFile extends AbstractInMemoryVirtualFile {
} }
return new VirtualFileAccessor() { return new VirtualFileAccessor() {
private int pos;
{
if (append) {
pos = size;
}
}
@Override @Override
public int read(int pos, byte[] buffer, int offset, int limit) { public int read(byte[] buffer, int offset, int limit) {
limit = Math.max(0, Math.min(size - pos, limit)); limit = Math.max(0, Math.min(size - pos, limit));
System.arraycopy(data, pos, buffer, offset, limit); if (limit > 0) {
System.arraycopy(data, pos, buffer, offset, limit);
pos += limit;
}
return limit; return limit;
} }
@Override @Override
public void write(int pos, byte[] buffer, int offset, int limit) { public void write(byte[] buffer, int offset, int limit) {
expandData(pos + limit); expandData(pos + limit);
System.arraycopy(buffer, offset, data, pos, limit); System.arraycopy(buffer, offset, data, pos, limit);
size = pos + limit; pos += limit;
if (pos > size) {
size = pos;
}
modify(); modify();
} }
@Override
public int tell() throws IOException {
return pos;
}
@Override
public void seek(int target) throws IOException {
pos = target;
}
@Override
public void skip(int amount) throws IOException {
pos += amount;
}
@Override @Override
public int size() { public int size() {
return size; return size;

View File

@ -23,9 +23,8 @@ import org.teavm.classlib.fs.VirtualFile;
import org.teavm.classlib.fs.VirtualFileAccessor; import org.teavm.classlib.fs.VirtualFileAccessor;
public class TFileInputStream extends InputStream { public class TFileInputStream extends InputStream {
private static final byte[] ONE_BYTE_BUFFER = new byte[1];
private VirtualFileAccessor accessor; private VirtualFileAccessor accessor;
private int pos;
private boolean eof;
public TFileInputStream(TFile file) throws FileNotFoundException { public TFileInputStream(TFile file) throws FileNotFoundException {
VirtualFile virtualFile = file.findVirtualFile(); VirtualFile virtualFile = file.findVirtualFile();
@ -52,16 +51,9 @@ public class TFileInputStream extends InputStream {
if (len == 0) { if (len == 0) {
return 0; return 0;
} }
if (eof) {
return -1;
}
ensureOpened(); ensureOpened();
int result = accessor.read(pos, b, off, len); int result = accessor.read(b, off, len);
pos += result; return result > 0 ? result : -1;
if (pos == accessor.size()) {
eof = true;
}
return result;
} }
@Override @Override
@ -70,25 +62,20 @@ public class TFileInputStream extends InputStream {
throw new IOException("Value must be positive: " + n); throw new IOException("Value must be positive: " + n);
} }
ensureOpened(); ensureOpened();
if (eof) { int last = accessor.tell();
return 0; accessor.skip((int) n - 1);
if (accessor.read(ONE_BYTE_BUFFER, 0, 1) < 1) {
int position = accessor.size();
accessor.seek(position);
return position - last;
} }
int newPos = Math.max(pos, Math.min(accessor.size(), pos + (int) n)); return n;
int result = newPos - pos;
pos = newPos;
if (result == 0) {
eof = true;
}
return result;
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
ensureOpened(); ensureOpened();
if (eof) { return Math.max(0, accessor.size() - accessor.tell());
return 0;
}
return Math.max(0, accessor.size() - pos);
} }
@Override @Override
@ -102,17 +89,9 @@ public class TFileInputStream extends InputStream {
@Override @Override
public int read() throws IOException { public int read() throws IOException {
ensureOpened(); ensureOpened();
if (eof) { byte[] buffer = ONE_BYTE_BUFFER;
return -1; int read = accessor.read(buffer, 0, 1);
} return read != 0 ? buffer[0] : -1;
byte[] buffer = new byte[1];
int read = accessor.read(pos, buffer, 0, 1);
if (read == 0) {
eof = true;
} else {
pos++;
}
return !eof ? buffer[0] : -1;
} }
private void ensureOpened() throws IOException { private void ensureOpened() throws IOException {

View File

@ -24,8 +24,8 @@ import org.teavm.classlib.fs.VirtualFile;
import org.teavm.classlib.fs.VirtualFileAccessor; import org.teavm.classlib.fs.VirtualFileAccessor;
public class TFileOutputStream extends OutputStream { public class TFileOutputStream extends OutputStream {
private static byte[] ONE_BYTE_BUFER = new byte[1];
private VirtualFileAccessor accessor; private VirtualFileAccessor accessor;
private int pos;
public TFileOutputStream(TFile file) throws FileNotFoundException { public TFileOutputStream(TFile file) throws FileNotFoundException {
this(file, false); this(file, false);
@ -57,10 +57,6 @@ public class TFileOutputStream extends OutputStream {
if (accessor == null) { if (accessor == null) {
throw new FileNotFoundException(); throw new FileNotFoundException();
} }
if (append) {
pos = -1;
}
} }
@Override @Override
@ -69,9 +65,8 @@ public class TFileOutputStream extends OutputStream {
if (off < 0 || len < 0 || off > b.length - len) { if (off < 0 || len < 0 || off > b.length - len) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
ensurePos(); ensureOpened();
accessor.write(pos, b, off, len); accessor.write(b, off, len);
pos += len;
} }
@Override @Override
@ -90,10 +85,10 @@ public class TFileOutputStream extends OutputStream {
@Override @Override
public void write(int b) throws IOException { public void write(int b) throws IOException {
ensurePos(); ensureOpened();
byte[] buffer = { (byte) b }; byte[] buffer = ONE_BYTE_BUFER;
accessor.write(pos, buffer, 0, 1); buffer[0] = (byte) b;
pos++; accessor.write(buffer, 0, 1);
} }
private void ensureOpened() throws IOException { private void ensureOpened() throws IOException {
@ -101,11 +96,4 @@ public class TFileOutputStream extends OutputStream {
throw new IOException("This stream is already closed"); throw new IOException("This stream is already closed");
} }
} }
private void ensurePos() throws IOException {
ensureOpened();
if (pos < 0) {
pos = accessor.size();
}
}
} }

View File

@ -29,10 +29,10 @@ import org.teavm.classlib.java.lang.TIndexOutOfBoundsException;
import org.teavm.classlib.java.lang.TNullPointerException; import org.teavm.classlib.java.lang.TNullPointerException;
public class TRandomAccessFile implements DataInput, DataOutput, Closeable { public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
private static final byte[] ONE_BYTE_BUFFER = new byte[1];
private boolean readOnly; private boolean readOnly;
private boolean autoFlush; private boolean autoFlush;
private VirtualFileAccessor accessor; private VirtualFileAccessor accessor;
private int pos;
private byte[] buff; private byte[] buff;
public TRandomAccessFile(String name, String mode) throws FileNotFoundException { public TRandomAccessFile(String name, String mode) throws FileNotFoundException {
@ -76,13 +76,9 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
if (off < 0 || len < 0 || off + len > b.length) { if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
if (pos >= accessor.size()) {
return -1;
}
ensureOpened(); ensureOpened();
int result = accessor.read(pos, b, off, len); int result = accessor.read(b, off, len);
pos += result; return result > 0 ? result : -1;
return result;
} }
public int read(byte[] b) throws IOException { public int read(byte[] b) throws IOException {
@ -92,8 +88,7 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
public int read() throws IOException { public int read() throws IOException {
ensureOpened(); ensureOpened();
byte[] buffer = new byte[1]; byte[] buffer = new byte[1];
int read = accessor.read(pos, buffer, 0, 1); int read = accessor.read(buffer, 0, 1);
pos += read;
return read > 0 ? buffer[0] : -1; return read > 0 ? buffer[0] : -1;
} }
@ -134,20 +129,24 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
public int skipBytes(int n) throws IOException { public int skipBytes(int n) throws IOException {
ensureOpened(); ensureOpened();
int newPos = Math.max(pos, Math.min(accessor.size(), pos)); int last = accessor.tell();
int result = newPos - pos; accessor.skip(n - 1);
pos = newPos; if (accessor.read(ONE_BYTE_BUFFER, 0, 1) < 1) {
return result; int position = accessor.size();
accessor.seek(position);
return position - last;
}
return n;
} }
public long getFilePointer() throws IOException { public long getFilePointer() throws IOException {
ensureOpened(); ensureOpened();
return pos; return accessor.tell();
} }
public void seek(long pos) throws IOException { public void seek(long pos) throws IOException {
ensureOpened(); ensureOpened();
this.pos = (int) pos; accessor.seek((int) pos);
} }
public long length() throws IOException { public long length() throws IOException {
@ -287,11 +286,10 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
public void write(int b) throws IOException { public void write(int b) throws IOException {
ensureOpened(); ensureOpened();
byte[] buffer = { (byte) b }; byte[] buffer = { (byte) b };
accessor.write(pos, buffer, 0, 1); accessor.write(buffer, 0, 1);
if (autoFlush) { if (autoFlush) {
accessor.flush(); accessor.flush();
} }
pos++;
} }
@Override @Override
@ -306,11 +304,10 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
ensureOpened(); ensureOpened();
accessor.write(pos, b, off, len); accessor.write(b, off, len);
if (autoFlush) { if (autoFlush) {
accessor.flush(); accessor.flush();
} }
pos += len;
} }
@Override @Override

View File

@ -566,7 +566,7 @@ int32_t teavm_file_flush(int64_t file) {
} }
int32_t teavm_file_seek(int64_t file, int32_t where, int32_t offset) { int32_t teavm_file_seek(int64_t file, int32_t where, int32_t offset) {
return SetFilePointer((HANDLE) file, offset, 0, where); return SetFilePointer((HANDLE) file, offset, 0, where) != INVALID_SET_FILE_POINTER;
} }
int32_t teavm_file_tell(int64_t file) { int32_t teavm_file_tell(int64_t file) {