Android FileStack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tomclaw.stack; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.EOFException; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.RandomAccessFile; | |
import java.util.ArrayList; | |
import java.util.EmptyStackException; | |
import java.util.List; | |
/** | |
* Created by ivsolkin on 05.07.16. | |
*/ | |
public abstract class FileStack<E extends StackItem> implements Stack<E> { | |
private File file; | |
private final List<Integer> offsets; | |
private RandomAccessFile stream; | |
protected FileStack(File file) { | |
this.file = file; | |
this.offsets = new ArrayList<>(); | |
} | |
private RandomAccessFile getStream() throws StackException { | |
try { | |
if (stream == null) { | |
stream = new RandomAccessFile(file, "rw"); | |
scan(); | |
} | |
long offset = getLastOffset(); | |
stream.seek(offset); | |
} catch (IOException ex) { | |
throw new StackException(ex); | |
} | |
return stream; | |
} | |
private int getLastOffset() { | |
int offset = 0; | |
if (!offsets.isEmpty()) { | |
offset = offsets.get(offsets.size() - 1); | |
} | |
return offset; | |
} | |
private void scan() throws IOException { | |
synchronized (offsets) { | |
stream.seek(0); | |
offsets.clear(); | |
int size, offset = 0; | |
try { | |
offsets.add(0); | |
while ((size = stream.readInt()) != -1) { | |
offset += 4; | |
offset += size; | |
offsets.add(offset); | |
stream.seek(offset); | |
} | |
} catch (EOFException ignored) { | |
} | |
} | |
} | |
@Override | |
public void push(E item) throws StackException { | |
try { | |
RandomAccessFile output = getStream(); | |
ByteArrayOutputStream arrayStream = new ByteArrayOutputStream(); | |
item.write(arrayStream); | |
byte[] data = arrayStream.toByteArray(); | |
output.writeInt(data.length); | |
output.write(data); | |
int offset = getLastOffset(); | |
offset += 4 + data.length; | |
offsets.add(offset); | |
arrayStream.close(); | |
} catch (IOException ex) { | |
throw new StackException(ex); | |
} | |
} | |
@Override | |
public E pop() throws StackException { | |
synchronized (offsets) { | |
if (isEmpty()) { | |
throw new StackException(new EmptyStackException()); | |
} | |
E item = createItem(); | |
try { | |
int offset = offsets.remove(offsets.size() - 1); | |
RandomAccessFile input = getStream(); | |
int size = input.readInt(); | |
byte[] data = new byte[size]; | |
input.readFully(data); | |
ByteArrayInputStream arrayStream = new ByteArrayInputStream(data); | |
item.read(arrayStream); | |
arrayStream.close(); | |
input.getChannel().truncate(offset - 4 - size); | |
} catch (IOException ex) { | |
throw new StackException(ex); | |
} | |
return item; | |
} | |
} | |
@Override | |
public E peek() throws StackException { | |
synchronized (offsets) { | |
E item = createItem(); | |
try { | |
RandomAccessFile input = getStream(); | |
if (isEmpty()) { | |
throw new StackException(new EmptyStackException()); | |
} | |
int offset = offsets.get(offsets.size() - 2); | |
input.seek(offset); | |
int size = input.readInt(); | |
byte[] data = new byte[size]; | |
input.readFully(data); | |
ByteArrayInputStream arrayStream = new ByteArrayInputStream(data); | |
item.read(arrayStream); | |
arrayStream.close(); | |
} catch (IOException ex) { | |
throw new StackException(ex); | |
} | |
return item; | |
} | |
} | |
public void clear() throws StackException { | |
synchronized (offsets) { | |
RandomAccessFile stream = getStream(); | |
offsets.clear(); | |
offsets.add(0); | |
try { | |
stream.getChannel().truncate(0); | |
} catch (IOException ex) { | |
throw new StackException(ex); | |
} | |
} | |
} | |
public boolean isEmpty() { | |
int offset = getLastOffset(); | |
return offset == 0; | |
} | |
public abstract E createItem(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tomclaw.stack; | |
/** | |
* Created by ivsolkin on 05.07.16. | |
*/ | |
public interface Stack<E extends StackItem> { | |
void push(E item) throws StackException; | |
E pop() throws StackException; | |
E peek() throws StackException; | |
void clear() throws StackException; | |
boolean isEmpty(); | |
class StackException extends Exception { | |
public StackException(Throwable cause) { | |
super(cause); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tomclaw.stack; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.OutputStream; | |
/** | |
* Created by ivsolkin on 05.07.16. | |
*/ | |
public interface StackItem { | |
void write(OutputStream output) throws IOException; | |
void read(InputStream input) throws IOException; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment