前几篇说了文件上传,都是上传到了WebRoot下的up目录,这样是不行的,文件多了性能就不行了。文件一般都是分目录存放的,这里讲建目录的一种算法。
先看结果,经过本算法建的目录,结构是这样的,还以up目录为例,新建的目录都建在up目录下:

WebRoot
--up
--目录1
--子目录1
--子目录2
--子目录3
--...
--子目录16
--目录2
--目录3
--...
--目录16

说明:

  1、本算法是,根据【文件名】进行哈希计算,最多只会创建16个目录,你需要做的是 把你上传的文件保存到本文件名计算出来的目录下。
  2、算法只会根据文件名计算出对应的目录是16个中的某一个,而不会自动创建一级、二级、三级目录来,这是你的事。
  3、一个目录不够用,一般来说,二级目录已经够了。这样目录总数是16*16是256个,如果一个目录存1000张图片的话,已经能存25万张图片了,不少了。

具体算法:

一:获取文件名的hashCode,例:
String name = "a.jpg";
int a = name.hashCode();//91057364
二:将hashCode转换成二进制:
//101011011010110110011010100 一共27位
String bin = Integer.toBinaryString(a);
//java 的int应该是4个字节,一个字节8位,一共32位。
// 但是例如a的hashCode对应的就是1100001(97)不足32位,需要补全位数为32位:
三:补全位数为32位:
//加上32个0,然后截取后32位
bin = "0000000000000000000000000000000"+bin;
bin =bin.substring(bin.length()-32);
//a.jpg 计算后:00000101011011010110110011010100
四:取最后一位
// 和 0xf 16进制的15 二进制是1111,做与运算
// 0000 0000 0000 0000 0000 0000 0000 1111
&
0000 0101 0110 1101 0110 1100 1101 0100
结果 0000 0000 0000 0000 0000 0000 0000 0100 int b = a & 0xf; //4 格式化为32位,好似没啥用:
bin = Integer.toBinaryString(b);
bin = "0000000000000000000000000000000"+bin;
bin =bin.substring(bin.length()-32);
五:转换为16进制:
String hex = Integer.toHexString(b);
System.err.println("第一层目录是:"+hex); --> 第一层目录是:4 这样第一层目录就计算出来了,第二层目录,如果还用最后4位计算,会和第一层一样,可以用倒数5-8位计算:
六:计算第二级目录
//将a 右移4位,高位补0,相当于5-8位变成了最末尾四位,取的是 1101 ,继续和0xf 与计算,其余同计算一级目录一样。
// 0000 0000 0000 0000 0000 0000 0000 1111
&
0000 0000 0101 0110 1101 0110 1100 1101
结果 0000 0000 0000 0000 0000 0000 0000 1101 int c = (a>>4) & 0xf; bin = Integer.toBinaryString(c);
bin = "0000000000000000000000000000000"+bin;
bin =bin.substring(bin.length()-32); hex = Integer.toHexString(c);
System.err.println("第二层的目录是:"+hex); -->第二层的目录是:d

这样就形成了/up/4/d目录,然后将本文件或图片放在这个目录下。

说明:0xf 是十六进制的15,转换成二进制是1111,和任何4位二进制进行&运算后,最大值也还是1111,最小值是0,所以最多只能创建16个目录。

 测试的java代码:

@Test
public void temp(){
String name = "a.jpg";
int a = name.hashCode();
System.err.println(a);//91057364
//转成二进制1000001111111100001001010
String bin = Integer.toBinaryString(a);
//位数 32位
bin = "0000000000000000000000000000000"+bin;
bin =bin.substring(bin.length()-32);
System.err.println(bin+","+bin.length()); //0xf表示16进制的15,二进制是1111,& a 可以取a的最后一位 1010
//
int b = a & 0xf;
System.err.println(b);//
bin = Integer.toBinaryString(b);//4的二进制 0100
System.out.println(Integer.toHexString(b));
bin = "0000000000000000000000000000000"+bin;
//格式化为 00000000000000000000000000001010
bin =bin.substring(bin.length()-32);
System.err.println(bin+","+bin.length()); //转换成16进制
String hex = Integer.toHexString(b);
System.err.println("第一层目录是:"+hex); int c = (a>>4) & 0xf;
System.err.println(c);
bin = Integer.toBinaryString(c);
bin = "0000000000000000000000000000000"+bin;
bin =bin.substring(bin.length()-32);
System.err.println(bin+","+bin.length()); hex = Integer.toHexString(c);
System.err.println("第二层的目录是:"+hex);
}

结果L:

91057364
00000101011011010110110011010100,32
4
00000000000000000000000000000100,32
第一层目录是:4
13
00000000000000000000000000001101,32
第二层的目录是:d
4



结合文件上传Servlet应用,用的还是fileupload组件:

package com.lhy.upload;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* 处理目录打散。
* 思想:对新生成的文件名进行二进制运算。
* 先取后一位 int x = hashcode & 0xf;
* 再取后第二位:int y = (hashCode >> 4) & 0xf;
* @author wangjianme
*
*/
@WebServlet(name="DirServlet",urlPatterns="/DirServlet")
public class DirServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("UTF-8");
//项目路径
String path = getServletContext().getRealPath("/up");
//第一步声明diskfileitemfactory工厂类,用于在指的磁盘上设置一个临时目录
DiskFileItemFactory disk = new DiskFileItemFactory();
disk.setRepository(new File("D:/tmp"));
//第二步:声明ServletFileUpoload,接收上面的临时目录
ServletFileUpload up = new ServletFileUpload(disk);
try {
//解析request
List<FileItem> list = up.parseRequest(request);
for (FileItem file : list) {
if(!file.isFormField()){
//不是普通表单域
String fileName = file.getName();
//如果是 C:\\xxx\\a.jpg格式,截取,不是不影响
fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
String extName = fileName.substring((fileName.indexOf(".")));//后缀 .jpg
String newName = UUID.randomUUID().toString().replace("-", "")+extName;
//第一步:获取新名称的hashcode
int code = newName.hashCode();
//第二步:获取后一位做为第一层目录
String dir1 = Integer.toHexString(code & 0xf);
System.err.println("第一层目录: "+dir1);
//获取第二层的目录
String dir2 = Integer.toHexString((code >> 4) & 0xf);
System.err.println("第二层目录: "+dir2);
String savePath = dir1+"/"+dir2;
//组成保存的目录
savePath = path+"/"+savePath;
//判断目录是否存在
File f = new File(savePath);
if(!f.exists()){
f.mkdirs(); //创建目录
}
//保存文件
file.write(new File(savePath+"/"+newName));
System.err.println("文件保存位置:\n"+savePath+"/"+newName);
//删除临时文件
file.delete(); //带路径保存到request
request.setAttribute("fileName",dir1+"/"+dir2+"/"+newName);
}
}
request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
} }

打印的信息:

第一层目录: f
第二层目录: d
文件保存位置:
D:\zhcw\apache-tomcat-7.0.69\webapps\Upload\up/f/d/826c14e14eed4eb895fac3b8335befa5.jpg

form表单:

<form action="<c:url value='/DirServlet'/>" method="post"
enctype="multipart/form-data">
你的图片:<input type="file" name="img"><br />
<input type="submit" />
</form>

shows.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<%-- <p>以下是你上传的文件</p>
<c:forEach items="${ups}" var="mm">
文件名:${mm.fileName}<br/>
类型:${mm.fileType}<br/>
大小:${mm.size}(bytes)
<hr/>
</c:forEach>
--%>
<hr color="blue"/>
<p>你上传的图片是:</p>
<img src="<c:url value='/up/${fileName}'/>"/>
</body>
</html>

上传:

服务器up目录:

z

展示页show.jsp:

多上传几张图片,可以看到会在up目录建目录:

上传的文件都被保存到了各自经过哈希计算后的目录,因为图片重命名是uuid是随机唯一的,所以被存放到那个目录不能确定。会被随机存放到生成的16个文件夹下。

目录打散-hash算法的更多相关文章

  1. 一致性 hash 算法(转)

    add by zhj:介绍了什么是一致性hash,以及实现一致性hash的一种算法. 原文:http://my.oschina.net/u/195065/blog/193614 目录[-] 一致性 h ...

  2. hash算法打散存储文件

    1.首先,为防止一个目录下面出现太多文件,所以使用hash算法打散存储 举例代码: int hashcode = filename.hashCode();//得到hashCode int dir1 = ...

  3. 【Java EE 学习 22 上】【文件上传】【目录打散】【文件重命名】

    1.文件上传概述 (1)使用<input type="file">的方式来声明一个文件域. (2)表单提交方式一定要是post方式才行 (3)表单属性enctype 默 ...

  4. Nginx+Memcache+一致性hash算法 实现页面分布式缓存(转)

    网站响应速度优化包括集群架构中很多方面的瓶颈因素,这里所说的将页面静态化.实现分布式高速缓存就是其中的一个很好的解决方案... 1)先来看看Nginx负载均衡 Nginx负载均衡依赖自带的 ngx_h ...

  5. 分布式缓存设计:一致性Hash算法

    缓存作为数据库前的一道屏障,它的可用性与缓存命中率都会直接影响到数据库,所以除了配置主从保证高可用之外还需要设计分布式缓存来扩充缓存的容量,将数据分布在多台机器上如果有一台不可用了对整体影响也比较小. ...

  6. Android NDK JNI 入门笔记-day04-NDK实现Hash算法

    * Android NDK JNI 入门笔记目录 * 开头 前面的学习,我们已经掌握了 NDK 开发的必备知识. 下一步就要多实践,通过创造问题并解决问题,来增加熟练度,提升经验. 日常开发中,经常会 ...

  7. Hash 算法与 Manacher 算法

    目录 前言 简单介绍 简述 Hash 冲突 离散化 基本结构 普通 Hash 简述 例题 字符串 Hash 简单介绍 核心思想 基本运算 二维字符串 Hash 例题 兔子与兔子 回文子串的最大长度 后 ...

  8. 编程艺术第十六~第二十章:全排列/跳台阶/奇偶调序,及一致性Hash算法

    目录(?)[+]   第十六~第二十章:全排列,跳台阶,奇偶排序,第一个只出现一次等问题 作者:July.2011.10.16.出处:http://blog.csdn.net/v_JULY_v. 引言 ...

  9. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

随机推荐

  1. StackView实现叠加在一起的图片循环移动像循环队列一样

    MainActivity.java public class MainActivity extends Activity {   StackView stackView; int[] imageIds ...

  2. public static void main(String[] args)说明

    /*public static void main(String[] args) 主函数特殊之处:1,格式是固定的.2,被jvm所识别和调用. public:因为权限必须是最大的.static:不需要 ...

  3. html 源码 引入样式

    post-title2 示例 sdf post-title 示例

  4. 求解1^2+2^2+3^2+4^2+...+n^2的方法(求解1平方加2平方加3平方...加n平方的和)

    利用公式 (n-1)3 = n3 -3n2 +3n-1 设 S3 = 13 +23 +33 +43 +...+n3 及 S2 = 12 +22 +32 +42 +...+n2 及 S1 = 1 +2 ...

  5. Windows Phone 放开政策 - 应用内支付(IAP)可加入三方支付

    Windows Phone 应用商店在 今年(2013)11月04号 修改了商店政策 允许公司账户的应用使用三方支付SDK. 通过 App certification requirements cha ...

  6. TFS Training for Kunlun bank (http://www.klb.cn/) 微软研发流程(ALM)管理培训会议(昆仑银行) 2016.09.21

    银行一直是微软技术的伤心地,由于历史原因,微软技术和产品一直很难进入到银行业务的核心区域,但是微软今年来的进步不少,在开发工具和平台方面已经连续攻克了几个典型的金融企业,例如农业银行,中国人保等. 应 ...

  7. html隐藏元素

    <body> <div>display:元素的位置不被占用</div> <div id="div1" style="displa ...

  8. ASP.NET Core使用Elasticsearch记录NLog日志

    ASP.NET Core使用Elasticsearch记录NLog日志 1.新建一个 ASP.NET Core项目 2.安装Nuge包 运行:Install-Package NLog.Web.AspN ...

  9. 移植Max中的控制器到Unity - 前言

    一切源自于一个ppt http://pan.baidu.com/s/1kT8x2V9 看到这个ppt之前,其实自己也想过将Max当中的一些约束移植到游戏中,一方面是那时候能力不足,另一方面还是自己不那 ...

  10. day85 ModuleForm Form组件

    1 forms组件与modelform组件 forms组件: https://www.cnblogs.com/yuanchenqi/articles/9036474.htmlmodelForm组件:h ...