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;
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;

View File

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

View File

@ -20,38 +20,50 @@ import org.teavm.classlib.fs.VirtualFileAccessor;
public class CVirtualFileAccessor implements VirtualFileAccessor {
private long file;
private int position;
public CVirtualFileAccessor(long file, int position) {
public CVirtualFileAccessor(long file) {
this.file = file;
this.position = position;
}
@Override
public int read(int pos, byte[] buffer, int offset, int limit) throws IOException {
ensurePosition(pos);
int bytesRead = CFileSystem.read(file, buffer, offset, limit);
position += bytesRead;
return bytesRead;
public int read(byte[] buffer, int offset, int limit) throws IOException {
return CFileSystem.read(file, buffer, offset, limit);
}
@Override
public void write(int pos, byte[] buffer, int offset, int limit) throws IOException {
ensurePosition(pos);
public void write(byte[] buffer, int offset, int limit) throws IOException {
int bytesWritten = CFileSystem.write(file, buffer, offset, limit);
if (bytesWritten < limit) {
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
public int size() throws IOException {
int current = CFileSystem.tell(file);
if (!CFileSystem.seek(file, 2, 0)) {
throw new IOException();
}
position = CFileSystem.tell(file);
return position;
int result = CFileSystem.tell(file);
if (!CFileSystem.seek(file, 0, current)) {
throw new IOException();
}
return result;
}
@Override
@ -59,11 +71,13 @@ public class CVirtualFileAccessor implements VirtualFileAccessor {
if (!CFileSystem.seek(file, 2, 0)) {
throw new IOException();
}
position = CFileSystem.tell(file);
int position = CFileSystem.tell(file);
if (position < size) {
byte[] zeros = new byte[4096];
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();
}
}
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() {
private int pos;
{
if (append) {
pos = size;
}
}
@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));
System.arraycopy(data, pos, buffer, offset, limit);
if (limit > 0) {
System.arraycopy(data, pos, buffer, offset, limit);
pos += limit;
}
return limit;
}
@Override
public void write(int pos, byte[] buffer, int offset, int limit) {
public void write(byte[] buffer, int offset, int limit) {
expandData(pos + limit);
System.arraycopy(buffer, offset, data, pos, limit);
size = pos + limit;
pos += limit;
if (pos > size) {
size = pos;
}
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
public int size() {
return size;

View File

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

View File

@ -24,8 +24,8 @@ import org.teavm.classlib.fs.VirtualFile;
import org.teavm.classlib.fs.VirtualFileAccessor;
public class TFileOutputStream extends OutputStream {
private static byte[] ONE_BYTE_BUFER = new byte[1];
private VirtualFileAccessor accessor;
private int pos;
public TFileOutputStream(TFile file) throws FileNotFoundException {
this(file, false);
@ -57,10 +57,6 @@ public class TFileOutputStream extends OutputStream {
if (accessor == null) {
throw new FileNotFoundException();
}
if (append) {
pos = -1;
}
}
@Override
@ -69,9 +65,8 @@ public class TFileOutputStream extends OutputStream {
if (off < 0 || len < 0 || off > b.length - len) {
throw new IndexOutOfBoundsException();
}
ensurePos();
accessor.write(pos, b, off, len);
pos += len;
ensureOpened();
accessor.write(b, off, len);
}
@Override
@ -90,10 +85,10 @@ public class TFileOutputStream extends OutputStream {
@Override
public void write(int b) throws IOException {
ensurePos();
byte[] buffer = { (byte) b };
accessor.write(pos, buffer, 0, 1);
pos++;
ensureOpened();
byte[] buffer = ONE_BYTE_BUFER;
buffer[0] = (byte) b;
accessor.write(buffer, 0, 1);
}
private void ensureOpened() throws IOException {
@ -101,11 +96,4 @@ public class TFileOutputStream extends OutputStream {
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;
public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
private static final byte[] ONE_BYTE_BUFFER = new byte[1];
private boolean readOnly;
private boolean autoFlush;
private VirtualFileAccessor accessor;
private int pos;
private byte[] buff;
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) {
throw new IndexOutOfBoundsException();
}
if (pos >= accessor.size()) {
return -1;
}
ensureOpened();
int result = accessor.read(pos, b, off, len);
pos += result;
return result;
int result = accessor.read(b, off, len);
return result > 0 ? result : -1;
}
public int read(byte[] b) throws IOException {
@ -92,8 +88,7 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
public int read() throws IOException {
ensureOpened();
byte[] buffer = new byte[1];
int read = accessor.read(pos, buffer, 0, 1);
pos += read;
int read = accessor.read(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 {
ensureOpened();
int newPos = Math.max(pos, Math.min(accessor.size(), pos));
int result = newPos - pos;
pos = newPos;
return result;
int last = accessor.tell();
accessor.skip(n - 1);
if (accessor.read(ONE_BYTE_BUFFER, 0, 1) < 1) {
int position = accessor.size();
accessor.seek(position);
return position - last;
}
return n;
}
public long getFilePointer() throws IOException {
ensureOpened();
return pos;
return accessor.tell();
}
public void seek(long pos) throws IOException {
ensureOpened();
this.pos = (int) pos;
accessor.seek((int) pos);
}
public long length() throws IOException {
@ -287,11 +286,10 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
public void write(int b) throws IOException {
ensureOpened();
byte[] buffer = { (byte) b };
accessor.write(pos, buffer, 0, 1);
accessor.write(buffer, 0, 1);
if (autoFlush) {
accessor.flush();
}
pos++;
}
@Override
@ -306,11 +304,10 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
throw new IndexOutOfBoundsException();
}
ensureOpened();
accessor.write(pos, b, off, len);
accessor.write(b, off, len);
if (autoFlush) {
accessor.flush();
}
pos += len;
}
@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) {
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) {