importjava.io.File;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;importjava.nio.charset.Charset;/*** Script: Encode.java Encode file or decode file. Java implementation and
* upgrade Encoding: UTF-8 Version: 0.2 Java version: 1.8 Usage: java Encode
* [encode | decode] filename [key]
**/
public classEncode {private static final String DEFAULT_KEY = "TESTKEY";private static final String DEFAULT_CHARSET = "UTF-8";private static final long SLEEP_TIME = 100;public booleanisEncode;publicMappedByteBuffer mappedBuffer;privateString filename;privateString charset;private byte[] keyBytes;privateEncodeThread[] workThreads;public Encode(booleanisEncode, String filename, String key) {this.isEncode =isEncode;this.filename =filename;this.charset =DEFAULT_CHARSET;this.keyBytes =key.getBytes(Charset.forName(charset));
}public voidrun() {try{//read file
RandomAccessFile raf = new RandomAccessFile(filename, "rw");
FileChannel channel=raf.getChannel();long fileLength =channel.size();int bufferCount = (int) Math.ceil((double) fileLength / (double) Integer.MAX_VALUE);if (bufferCount == 0) {
channel.close();
raf.close();return;
}int bufferIndex = 0;long preLength = 0;//repeat part
long regionSize =Integer.MAX_VALUE;if (fileLength - preLength
regionSize= fileLength -preLength;
}
mappedBuffer=channel.map(FileChannel.MapMode.READ_WRITE, preLength, regionSize);
preLength+=regionSize;//create work threads
int threadCount =keyBytes.length;
System.out.println("File size: " + fileLength + ", buffer count: " + bufferCount + ", thread count: " +threadCount);long startTime =System.currentTimeMillis();
System.out.println("Start time: " + startTime + "ms");
System.out.println("Buffer " + bufferIndex + " start ...");
workThreads= newEncodeThread[threadCount];for (int i = 0; i < threadCount; i++) {
workThreads[i]= new EncodeThread(this, keyBytes[i], keyBytes.length, i);
workThreads[i].start();
}//loop
while (true) {
Thread.sleep(SLEEP_TIME);//wait until all threads completed
boolean completed = true;for (int i = 0; i < workThreads.length; i++) {if (!workThreads[i].isCompleted()) {
completed= false;break;
}
}if (!completed) {continue;
}//check if finished
bufferIndex++;if (bufferIndex >=bufferCount) {//stop threads
for (int i = 0; i < workThreads.length; i++) {
workThreads[i].flag= false;
}break;
}//repeat part
regionSize =Integer.MAX_VALUE;if (fileLength - preLength
regionSize= fileLength -preLength;
}
mappedBuffer=channel.map(FileChannel.MapMode.READ_WRITE, preLength, regionSize);
preLength+=regionSize;//restart threads
System.out.println("Buffer " + bufferIndex + " start ...");for (int i = 0; i < workThreads.length; i++) {
workThreads[i].restart();
}
}//over loop
while (true) {
Thread.sleep(SLEEP_TIME);boolean isOver = true;for (int i = 0; i < workThreads.length; i++) {if(workThreads[i].isAlive()) {
isOver= false;break;
}
}if(isOver) {break;
}
}//close file relatives
channel.close();
raf.close();long endTime =System.currentTimeMillis();
System.out.println("End time: " + endTime + "ms, use time: " + (endTime - startTime) + "ms");
System.out.println("ok!");
}catch (IOException |InterruptedException e) {
e.printStackTrace();
}
}public static voidmain(String[] args) {
String usage= "Usage: java -jar encode.jar [encode | decode] filename [key]";//parse args
if (args.length < 2) {
System.out.println("There must be two or more arguments!");
System.out.println(usage);return;
}if (!args[0].equals("encode") && !args[0].equals("decode")) {
System.out.println("The first argument must be \"encode\" or \"decode\"");
System.out.println(usage);return;
}boolean isEncode = (args[0].equals("encode"));
String filename= args[1];
File file= newFile(filename);if (!file.isFile()) {
System.out.println("The file doesn't exist!");
System.out.println(usage);return;
}
String key=DEFAULT_KEY;if (args.length > 2) {
key= args[2];
}//encode or decode
newEncode(isEncode, filename, key).run();
}
}class EncodeThread extendsThread {private static final long SLEEP_TIME = 50;public booleanflag;privateEncode encoder;private intkey;private longdataIndex;private intinterval;private intregionSize;private booleancompleted;public EncodeThread(Encode encoder, byte key, int interval, intindex) {this.encoder =encoder;this.key = key & 0xff;this.dataIndex =index;this.interval =interval;this.regionSize =encoder.mappedBuffer.limit();this.completed = false;this.flag = true;
}public voidrestart() {this.dataIndex -=regionSize;
regionSize=encoder.mappedBuffer.limit();
completed= false;
}public booleanisCompleted() {returncompleted;
}
@Overridepublic voidrun() {try{if(encoder.isEncode) {
encode();
}else{
decode();
}
}catch(InterruptedException e) {
e.printStackTrace();
}
}private void encode() throwsInterruptedException {while(flag) {//completed here ensure restart() synchronized
if(completed) {
Thread.sleep(SLEEP_TIME);continue;
}if (dataIndex >=regionSize) {
completed= true;
System.out.println("Encode thread " + this.getName() + " is completed!");continue;
}//do encode
byte b = encoder.mappedBuffer.get((int) dataIndex);//added as unsigned byte
b = (byte) (((b & 0xff) + key) % 256);
encoder.mappedBuffer.put((int) dataIndex, b);
dataIndex+=interval;
}
}private void decode() throwsInterruptedException {while(flag) {//completed here ensure restart() synchronized
if(completed) {
Thread.sleep(SLEEP_TIME);continue;
}if (dataIndex >=regionSize) {
completed= true;
System.out.println("Encode thread " + this.getName() + " is completed!");continue;
}//do decode
byte b = encoder.mappedBuffer.get((int) dataIndex);//substracted as unsigned byte
b = (byte) (((b & 0xff) + 256 - key) % 256);
encoder.mappedBuffer.put((int) dataIndex, b);
dataIndex+=interval;
}
}
}