zoukankan      html  css  js  c++  java
  • 加密文件之Java改进版

    对应Python版:加密文件之Python版
    Java版比Python版要快得多,两个版本不在一个量级上。在加密解密1G大文件时,Java版花费的时间是秒级,而Python版花费的时间是10分钟级。

    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.MappedByteBuffer;
    import java.nio.channels.FileChannel;
    import java.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 class Encode {
    
        private static final String DEFAULT_KEY = "TESTKEY";
        private static final String DEFAULT_CHARSET = "UTF-8";
        private static final long SLEEP_TIME = 100;
    
        public boolean isEncode;
        public MappedByteBuffer mappedBuffer;
    
        private String filename;
        private String charset;
        private byte[] keyBytes;
    
        private EncodeThread[] workThreads;
    
        public Encode(boolean isEncode, String filename, String key) {
            this.isEncode = isEncode;
            this.filename = filename;
            this.charset = DEFAULT_CHARSET;
            this.keyBytes = key.getBytes(Charset.forName(charset));
        }
    
        public void run() {
            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 < Integer.MAX_VALUE) {
                    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 = new EncodeThread[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 < Integer.MAX_VALUE) {
                        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 void main(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 = new File(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
            new Encode(isEncode, filename, key).run();
        }
    
    }
    
    class EncodeThread extends Thread {
    
        private static final long SLEEP_TIME = 50;
    
        public boolean flag;
    
        private Encode encoder;
        private int key;
        private long dataIndex;
        private int interval;
        private int regionSize;
        private boolean completed;
    
        public EncodeThread(Encode encoder, byte key, int interval, int index) {
            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 void restart() {
            this.dataIndex -= regionSize;
            regionSize = encoder.mappedBuffer.limit();
            completed = false;
        }
    
        public boolean isCompleted() {
            return completed;
        }
    
        @Override
        public void run() {
            try {
                if (encoder.isEncode) {
                    encode();
                } else {
                    decode();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        private void encode() throws InterruptedException {
            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() throws InterruptedException {
            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;
            }
        }
    
    }
  • 相关阅读:
    接上一篇:(四) 控制反转(IOC)/ 依赖注入(DI)
    日常踩坑-------新手使用idea
    聚集索引和非聚集索引的区别
    mysql锁
    常用算法
    sql join查询语句
    bitmap原理和redis bitmap应用
    nginx反向代理、负载均衡配置
    nginx工作模式
    PHP常用设计模式
  • 原文地址:https://www.cnblogs.com/alwu007/p/8111581.html
Copyright © 2011-2022 走看看