Java 生成任意位数永不重复的随机数策略实现

来源:互联网 发布:sql 外键必须是主键吗 编辑:程序博客网 时间:2024/05/29 19:23

原文:http://blog.csdn.net/shzy1988/article/details/54970421?locationNum=1&fps=1

在项目中遇到客户一个需求,ID的生成策略:长度8位,用户在知道自己的ID(如:10000018)后,不能通过ID来推测相关信息,如用户可能推测我是第18个注册用户,上一个注册用户的ID是10000017,这样就不能很好的保护账号安全了,可以凭证推测数据来进行不法之事。

经过网上查找和思考,便有了如下的解决方案:

  • 生成一个装有1-99999999数值的数组
  • 将数值内的值随机打乱
  • 将数值的值分开保存到不同的文件(txt)中
  • 获取ID的时候,可以随机从任意一文件中获取第一行的ID值,然后将剩余行的ID值重写写会原文件
  • 如果文件中的ID值已经取完则删除

逻辑很简单,就看实现了,代码如下:

生成ID并保存到硬盘

 /**     * 生成1-99999999的数字编码保存到硬盘     */    private static void generateAppCode2Disk(){        int begin = 1;          int end = 99999999;          int count = begin + end;          //生成1到99999999的所有整数          int[] codes = new int[count + 1];          for (int i = begin; i <= end; i++){              codes[i] = i;          }        //随机交换数据          int index = 0;        int tempCode = 0;        Random random = new Random();        for (int i = begin; i <= end; i++){              index = random.nextInt(count+1);              tempCode = codes[index];              codes[index] = codes[i];              codes[i] = tempCode;          }        //生成1000个文件,每个文件包含100000个appCode        StringBuilder sb = new StringBuilder();        int flag = 100000;        System.out.println("***********开始**********");        try {            for(int i = begin; i <= end; i++){                sb.append(codes[i]).append("\n");                if(i == end || i%flag == 0){                    File folder = new File("D:/IDGenerate");                    if(!folder.isDirectory()){                        folder.mkdir();                    }                    if(i==end){                        i = end +1;                    }                    File file = new File("D:/IDGenerate/ID_"+(i/flag)+".txt");                    if (!file.exists()) {                        file.createNewFile();                    }                    BufferedWriter bw=new BufferedWriter(new FileWriter(file.getAbsoluteFile()));                    bw.write(sb.toString());                    bw.flush();                    bw.close();                    sb = new StringBuilder();                    System.out.println("当前i值:"+i+"第"+(i/flag)+"个文件生成成功!");                }            }            System.out.println("***********结束**********");        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }

获取ID

//获取唯一8位ID    public String createAppCode(){        BufferedWriter bw = null;        BufferedReader br = null;        FileReader fr = null;        FileWriter fw = null;        try {            String dir = "D:/";            if(StringUtils.isBlank(dir)){                throw new Exception("获取文件路径为空");            }            File rootFile = new File(dir);            String[] fileNames = rootFile.list();            if(fileNames == null || fileNames.length == 0){                throw new Exception("路径不正确,或者ID已经分配完毕,请联系管理员");            }            //获取第一个文件            fr=new FileReader(dir+"/"+fileNames[0]);//获取文件流            br = new BufferedReader(fr); //将流整体读取。            StringBuilder sb = new StringBuilder();            String appCode = "";            String temp;            int count =1;            while(!StringUtils.isBlank(temp=br.readLine())){                if(count == 1){                    count++;                    appCode = temp;                    continue;                }                else{                    sb.append(temp).append("\n");                }            }            br.close();            fr.close();            if(!StringUtils.isBlank(appCode)){                //判断文件内容是否还有下一行                if(sb.length()<=0){                    File delFile = new File(dir+"/"+fileNames[0]);                    if(delFile.exists()){                        delFile.delete();//删掉                    }                }                else{                    //将剩余内容重写写回文件                    fw = new FileWriter(dir+"/"+fileNames[0]);                    bw=new BufferedWriter(fw);                    bw.write(sb.toString());                    bw.flush();                    bw.close();                    fw.close();                }                String prex = "00000000";                appCode = prex.substring(0,prex.length()-appCode.length())+appCode;                return appCode;            }            else{                throw new Exception("文件中内容为空");            }        } catch (Exception e) {            log.error("获取ID error:"+e.getMessage());            return null;        } finally{            try {                if(bw != null)bw.close();                if(br != null)br.close();                if(fr != null)fr.close();                if(fw != null)fw.close();            } catch (IOException e) {                log.error("关闭文件流文件异常:"+e.getMessage());            }        }    }

这样将生成的ID分成1000个文件保存到硬盘,取数据的时候从任意文件中取都可,这样能很好的保证了随机,不重复,而且在测试的时候发现效率还不错,内存,CPU的使用都微乎其微。

为了更好的优化获取ID效率,可以有如下改进:

  • 将ID保存到更多的文件中,这样文件的容量就可以很小,加载的时候就更快
  • 预读ID,可以提前预读50,100等数量的ID保存到list中,直接从内存取数据就更快了,不过这逻辑就复杂了很多,要保证list的数据和硬盘数据的同步,就需要更多的代码来判断了

    此文章供大家参考,大家有什么好的建议,算法都可以提出来交流的!

2 0
原创粉丝点击