A long time ago, I coded a file splitter and joiner called Afsj. Project hosted at Sourceforge.
Today I will explain object-oriented programming concepts through afsj.
Afsj is a good source code with a nice hierarchy. If you are a beginner, Afsj is a good resource for learning object-oriented programming in Java. That project is small and medium. And you can read (understand) the source code easily.
1. Coding an extension generator. If the input is a file name such as "file.001" the generator generates next string "file.002". When user uses afsj joiner, he just provide/prompt the first file to join. And the joiner automatically find next file to join. In common case, users provide first file, for instance: a.001, our joiner find next files, a.002, a.003... automatically in same directory or user provide next file location.
We define an interface, an abstract class and some classes inherit from it. IExtensionGenerator -> AbstExtensionGenerator -> StandardExtensionGenerator.
src/main/java/khang/iwcjff/afsj/IExtensionGenerator.java:
public interface IExtensionGenerator {
boolean hasNext();
String next();
void setPrefix(String prefx);
String getPrefix();
}
src/main/java/khang/iwcjff/afsj/AbstExtensionGenerator.java:
public abstract class AbstExtensionGenerator implements IExtensionGenerator {
protected int max;
protected int current;
@Override public boolean hasNext() {
return current < max;
}
}
src/main/java/khang/iwcjff/afsj/StandardExtensionGenerator.java (focus on next() method):
public class StandardExtensionGenerator extends AbstExtensionGenerator {
private int totalDigits;
private int prefixLength;
public StandardExtensionGenerator(int nmin, int nmax) {
if (nmin < 1 || nmin > nmax) {
throw new IllegalArgumentException();
}
// i don't like this.min = min styles
// set the current number
max = nmax;
current = nmin - 1;
// set the total digits of file name extensions
int length = String.valueOf(nmax).length();
totalDigits = (length > 3) ? length: 3;
prefixLength = totalDigits - String.valueOf(current).length();
}
@Override public String next() {
prefixLength = totalDigits - String.valueOf(++current).length();
String result = ".";
for(int i = 0; i < prefixLength; ++i) result += "0";
return (result + String.valueOf(current));
}
// for compatibility
@Override public void setPrefix(String prefx) {
throw new UnsupportedOperationException();
}
@Override public String getPrefix() { return ""; }
}
2. Coding a file joiner. Implementing easily by applying Java built-in SequenceInputStream
src/main/java/khang/iwcjff/afsj/AjikJoiner.java:
SequenceInputStream f = new SequenceInputStream(Collections.enumeration(fisCollection));
// create new file ouput on disk
fileDest = new FileOutputStream(fileOutput);
byte[] inBytes = new byte[chunk];
int byteRead;
while((byteRead = f.read(inBytes)) != -1) {
bytesRead += byteRead;
fileDest.write(inBytes, 0, byteRead);
}
fileDest.flush();
f.close();
Important techniques: Each time we read a chunk of bytes into a buffer and write those bytes from this buffer into file destination (aka: write file in append mode).
3. Coding a file joiner. Firstly we need to know the number of parts will be splitted:
src/main/java/khang/iwcjff/afsj/AjikSplitter.java:
// get the total size of source
totalSize = fileInput.length();
partSize = psize;
totalParts = (long)Math.ceil((double)totalSize / partSize);
No comments:
Post a Comment