分类 Hadoop 下的文章

hadoop客户端该如何配置

Hadoop集群主要是由三部分组成的:主节点、从节点和客户端,即master、slave和client。我们在搭建hadoop集群的时候通常只考虑了主节点和从节点的搭建,却忽略了客户端。当我们搭建完成后,我们在其中的一台机器上运行wordcount或者计算π时,实际上我们已经默认将一台主节点或者一台从节点当做客户端来使用了,但是,如果我想把客户端独立,该如何单独配置客户端呢?
答案其实很简单,只要在配置slave的时候,不要把客户端添加到slave里,即客户端和hadoop集群其他的节点配置是一摸一样的,但不参与运算
完整的hadoop集群搭建过程,请参考:《Hadoop集群搭建详细简明教程》

slave配置

slave配置

行存储和列存储比较–理解hbase的基础

目前大数据存储有两种方案可供选择:行存储和列存储。业界对两种存储方案有很多争持,集中焦点是:谁能够更有效地处理海量数据,且兼顾安全、可靠、完整性。从目前发展情况看,关系数据库已经不适应这种巨大的存储量和计算要求,基本是淘汰出局。在已知的几种大数据处理软件中,Hadoop的HBase采用列存储,MongoDB是文档型的行存储,Lexst是二进制型的行存储。在这里,我不讨论这些软件的技术和优缺点,只围绕机械磁盘的物理特质,分析行存储和列存储的存储特点,以及由此产生的一些问题和解决办法。
一.结构布局
行存储数据排列

行存储

行存储


列存储数据排列
列存储

列存储


表格的灰色背景部分表示行列结构,白色背景部分表示数据的物理分布,两种存储的数据都是从上至下,从左向右的排列。行是列的组合,行存储以一行记录为单位,列存储以列数据集合单位,或称列族(column family)。行存储的读写过程是一致的,都是从第一列开始,到最后一列结束。列存储的读取是列数据集中的一段或者全部数据,写入时,一行记录被拆分为多列,每一列数据追加到对应列的末尾处。
二. 对比
从上面表格可以看出,行存储的写入是一次完成。如果这种写入建立在操作系统的文件系统上,可以保证写入过程的成功或者失败,数据的完整性因此可以确定。列存储由于需要把一行记录拆分成单列保存,写入次数明显比行存储多,再加上磁头需要在盘片上移动和定位花费的时间,实际时间消耗会更大。所以,行存储在写入上占有很大的优势。
还有数据修改,这实际也是一次写入过程。不同的是,数据修改是对磁盘上的记录做删除标记。行存储是在指定位置写入一次,列存储是将磁盘定位到多个列上分别写入,这个过程仍是行存储的列数倍。所以,数据修改也是以行存储占优。 数据读取时,行存储通常将一行数据完全读出,如果只需要其中几列数据的情况,就会存在冗余列,出于缩短处理时间的考量,消除冗余列的过程通常是在内存中进行的。列存储每次读取的数据是集合的一段或者全部,如果读取多列时,就需要移动磁头,再次定位到下一列的位置继续读取。 再谈两种存储的数据分布。由于列存储的每一列数据类型是同质的,不存在二义性问题。比如说某列数据类型为整型(int),那么它的数据集合一定是整型数据。这种情况使数据解析变得十分容易。相比之下,行存储则要复杂得多,因为在一行记录中保存了多种类型的数据,数据解析需要在多种数据类型之间频繁转换,这个操作很消耗CPU,增加了解析的时间。所以,列存储的解析过程更有利于分析大数据。
三. 优化
显而易见,两种存储格式都有各自的优缺点:行存储的写入是一次性完成,消耗的时间比列存储少,并且能够保证数据的完整性,缺点是数据读取过程中会产生冗余数据,如果只有少量数据,此影响可以忽略;数量大可能会影响到数据的处理效率。列存储在写入效率、保证数据完整性上都不如行存储,它的优势是在读取过程,不会产生冗余数据,这对数据完整性要求不高的大数据处理领域,比如互联网,犹为重要。
改进集中在两方面:行存储读取过程中避免产生冗余数据,列存储提高读写效率。
如何改进它们的缺点,并保证优点呢?
行存储的改进:减少冗余数据首先是用户在定义数据时避免冗余列的产生;其次是优化数据存储记录结构,保证从磁盘读出的数据进入内存后,能够被快速分解,消除冗余列。要知道,目前市场上即使最低端CPU和内存的速度也比机械磁盘快上100-1000倍。如果用上高端的硬件配置,这个处理过程还要更快。
列存储的两点改进:1.在计算机上安装多块硬盘,以多线程并行的方式读写它们。多块硬盘并行工作可以减少磁盘读写竞用,这种方式对提高处理效率优势十分明显。缺点是需要更多的硬盘,这会增加投入成本,在大规模数据处理应用中是不小的数目,运营商需要认真考虑这个问题。2.对写过程中的数据完整性问题,可考虑在写入过程中加入类似关系数据库的“回滚”机制,当某一列发生写入失败时,此前写入的数据全部失效,同时加入散列码校验,进一步保证数据完整性。
这两种存储方案还有一个共同改进的地方:频繁的小量的数据写入对磁盘影响很大,更好的解决办法是将数据在内存中暂时保存并整理,达到一定数量后,一次性写入磁盘,这样消耗时间更少一些。目前机械磁盘的写入速度在20M-50M/秒之间,能够以批量的方式写入磁盘,效果也是不错的。
四. 总结
两种存储格式各自的特性都决定了它们不可能是完美的解决方案。 如果首要考虑是数据的完整性和可靠性,那么行存储是不二选择,列存储只有在增加磁盘并改进软件设计后才能接近这样的目标。如果以保存数据为主,行存储的写入性能比列存储高很多。在需要频繁读取单列集合数据的应用中,列存储是最合适的。如果每次读取多列,两个方案可酌情选择:采用行存储时,设计中应考虑减少或避免冗余列;若采用列存储方案,为保证读写入效率,每列数据尽可能分别保存到不同的磁盘上,多个线程并行读写各自的数据,这样避免了磁盘竞用的同时也提高了处理效率。 无论选择哪种方案,将同内容数据聚凑在一起都是必须的,这是减少磁头在磁盘上的移动,提高数据读取时间的有效办法。
行存储列存储

行存储列存储


http://www.infoq.com/cn/articles/bigdata-store-choose

Hadoop 2.0激活大数据应用开发

Hadoop生态系统还在不断演进。倒退几年,我们还仅仅把Hadoop看作是HDFS(分布式文件系统)、MapReduce(软件编程模型)以及一些元素(工具与API)的组合,它们逐渐成为了大数据的代名词。
然而上周在圣何塞举行的Hadoop峰会2013让我们意识到,Hadoop已经发生了本质上的变化。Hadoop 2.0登上历史舞台,随之而来的增强特性为我们带来了一套新的数据编程方式,尽管依然依附于Hadoop,但它已经为我们提供了打破Hadoop固有印象的可能。
在Hadoop 2.0中,新增强的功能虽然还是围绕HDFS以及相关组件,如HBase数据库、Hive数据仓库以及Knox安全网关等,但是最引人关注的还是2.0中的YARN组件。YARN的名称来自于字母缩写“Yet Another Resource Manager”,直译可以称为另一个资源管理器。利用YARN,用户可以完全放弃原有的MapReduce,通过与批处理完全不同的新的交互方式来运行Hadoop。
商业智能咨询顾问Colin White 指出,Hadoop 2.0的HDFS对架构进行了重新设计,从而消除了某些单点故障的隐患。这仅仅是开始,更关键的进步在于API层面。White表示:“具有革命性的变化来自于YARN,它使得我们可以使用另外一种文件系统,为环境添加更多的灵活性,这是企业级用户最想要的功能。”
事实上,很多用户已经在讨论在Hadoop中运行其他的文件系统,比如IBM的通用并行文件系统,或者用Lustre的文件系统进行高性能集群计算。而YARN的出现,使得MapReduce不再是必需品,而变成了一种选项。
  Gartner分析师Merv Adrian表示,“核心Hadoop”的概念在未来也许将不复存在,数据架构中类似可插拔的选项已经提上了Hadoop的议事日程,任何层面都不再是只提供唯一解决方案,万事皆有可能。
  Hadoop以及相关工具在近几年中层出不穷,Adrian向TechTarget记者表示,当Web应用开发者开始决定创建一个专有数据存储之后,他们往往会选择把它开源。
  Adrian说:“Hadoop社区是吸引创新的支点,但Gartner建议企业用户尽量使用商用版的Hadoop解决方案。免费下载的开源产品可以用来进行沙盒实验。”
  用Adrian的话来说,近些年来发生的最大变化是数据存储的“爆炸”,许多都跟NoSQL相关。人们开始质疑传统SQL数据模型存在的弊端,而Hadoop更像是一个大的帐篷,把包括NoSQL运动在内的所有数据相关变化全部包容在内。
  这一变化的原因包括三点:首先,大规模扩展的关系型数据库系统成本过于昂贵;其次,数据库Schema的限制往往成为创新的阻力;最后,关系型数据库不能很好地支持Web应用。
  现在,关注各种类型数据存储的架构师和开发者都能够在Hadoop生态系统中找到他们想要的。在Hadoop峰会上,关于新范式的热情是显而易见的,就如同几年前Java和AJAX一样。Java语言是新时代应用开发的起点,AJAX也同样。如今的Hadoop与AJAX很像,成为一个符号化的概念,而围绕它的技术或者编程语言才是实体。
  很重要的一个观点是,Hadoop社区在做的事情代表了数据管理的一个主要发展方向。这些有着奇奇怪怪名称的开源工具以及API将能够让开发者以更创新的方式开发大数据应用,而这在之前是难以实现的。
http://www.searchbi.com.cn/showcontent_74554.htm

Java开发者不一定最适合Hadoop

JNAN DASH的一位(IBM数据仓库BI)专家朋友几周前参加了在圣何塞举行的Hadoop会议。两年前也是这个时间,他参加了当时在纽约的Hadoop会议,但当时仅有200人,而这次不仅有2000多人参加,并且门票早已销售一空。显然,这很直观地证明了Hadoop会议引发了业内高度的兴趣。不止如此,他发现每一个主题演讲的PPT中有关Hadoop技术的幻灯片中都提到“我们正在招聘(we are hiring)”。
人才缺乏由此可见一斑。作为一个能够对大量数据进行分布式处理的软件框架,Hadoop可靠、高效而可伸缩。由于Hadoop很容易实现对搜索关键字进行内容分类,并可以通过并行处理加快处理速度,所以受到更行业的欢迎。而Hadoop带有用Java 语言编写的框架,因此在Linux生产平台上很理想。而在Hadoop上的应用程序也可以使用其他语言编写,比如 C++。
事实上,Hadoop使廉价服务器的大规模并行计算成为可能。企业可以收集更多的数据,保留时间可以更长,并对所有数据可以进行之前由于成本、复杂性和缺乏工具而无法进行的分析。互联网企业几乎都是Hadoop的用户,而如eBay、Facebook、LinkedIn、Netflix和Twitte的创新型尝试也为其他数据密集型行业,如金融、科技、电信和政府的应用铺平了道路。越来越多的IT人发现,Hadoop已经在其架构规划中占据一席之地。但Hadoop成为绝对主流的另一大挑战是,如何找到擅长这一技术的专业人才。
Cloudera、IBM、Hortonworks、MapR是值得关注的四家Hadoop企业。而这几家都有大量投资于培训计划,教IT专业人员如何部署,配置和管理Hadoop的产品。显然,这些企业清楚地认识到,人才将是限制Hadoop企业级应用发展不容回避的问题。
但另一面,Cloudera的客户解决方案副总裁Omer Trajman却表示:“直接雇佣新人是不可思议的。”在他看来,“最可行的办法是在企业内部寻找人才来学习Hadoop。”因为,“最成功的公司一般不需要大举招聘。因为在企业内部,完全可以了解员工的基本技能,比如谁有科学、统计、数据处理、利用Java来开发和分析的背景,找到这些已经在相关业务领域中拥有专门知识的人才,然后再做Hadoop培训,教会他们如何使用Hadoop工具,就可以成为合格的人才。”
当然,随着对Hadoop的重视程度更高,业内学习Hadoop的人也在增加。相关业内人士表示:“几年前我在面试技术人员时,问他们是否认识Hadoop?而通常的答案是ha-what?但是如今,知道和运用Hadoop的人已经越来越多了。”
不过,问题也随之而来。企业需要明确什么样类型的人是适合招聘的Hadoop人才?
“我们原以为需要找一个铁杆的Java开发者”,MapR商业分销Return Path的负责人表示,“但事实并非如此。最适合Hadoop的人才不一定是Java工程师。反而是那些能够理解集群、收集一些工具,指出如何实现协同工作,并能处理Hadoop生态系统中出现的许多问题,而并不仅限于Hadoop 1.0的人才是我们需要的技能型人才。”
这篇文章发表在:2012-07-13

招聘hadoop方向的开发人员主要看重的是什么能力?

想请教一下,在招聘hadoop方向的开发人员时,和招聘web应用开发人员的要求有什么不同,是否会更看重算法设计能力。对于目前从事web开发,想要转至hadoop方向的程序员有没有什么好的建议呢?谢谢!
我的规划中,是没有“专业Hadoop程序员”这个概念的。毕竟这只是一个框架,就好像不能叫“专业Mysql管理员”一样,我们应该是从事分布式计算的工程师,或者云计算工程师。
做这个领域,我认为有两个方面的能力是重要的,技术架构能力和业务数据敏感。
针对目前从事Web开发的工程师,我第一个建议是提高视野。很多Web工程师只认识Web框架内的东西,这阻碍他理解批处理系统的结构。
第二个建议是要对业务数据敏感,大部分Web工程师长期接触一线的需求,这方面是没有问题的。
你说的算法设计能力,我认为是技术能力的一部分。在入门阶段不是很紧迫,做1-2年以后会遇到需要优化的算法问题。
关于第一个问题,招聘时的区别。在我这里是没有的,任何领域的开发人员我们都要求 1 基础扎实 2 逻辑清晰 3 沟通流畅,知识可以慢慢学,但是素质不容易改。
知乎: http://www.zhihu.com/question/19956296

比Hive高效7倍 Facebook推新一代查询引擎Presto

在Facebook总部的一次开发者会议上,这个社交网络巨头的工程师透露,他们正在使用新的自主研发的查询引擎Presto,在已有的250PB的庞大数据仓库上进行交互式分析。
据Martin Traverso工程师透露,有超过850名Facebook工程师每天用它来扫描超过320TB的数据。在以前,我们的科学家和分析师一直依靠Hive来做数据分析。但Hive是专为批处理设计的。但随着数据越来越多,Hive已不能满足我们的需求。虽然我们还有其他比Hive更快的工具,但它们要么在功能有所限制要么就太简单,以至于无法操作我们庞大的数据仓库。而在过去的几个月中,我们一直使用Presto来填补这方面的空白。
Hive是Facebook在几年前专为Hadoop打造的一款数据仓库工具。因为它主要依赖MapReduce进行运行,所以随着年龄的上升,其在速度上已不能满足日益增长的数据要求。浏览一个完整的数据集可能要花费几分到几小时,这完全是不切实际的。
Traverso还表示,使用Presto进行简单的查询只需要几百毫秒,即使是非常复杂的查询,也只需数分钟即可完成,它在内存中运行,并且不会向磁盘写入。
虽然看起来Presto如同Facebook版的Cloudera Impala SQL查询引擎,或与Hortonworks在Stinger项目中所做的事情相似,但这是按照Facebook规模为实现更快操作而定制的版本。Presto并不会与其他商业产品进行竞争,但它会很快让大数据行业产生不小的震动。并且Facebook打算在今年秋天以开源的形式发布Presto。
Facebook的工程经理Ravi Murthy表示,随着用户量地不断增长,数据仓库也在快速增长,它比四年前要大4000倍。Murthy 也表示,在接下来几年,数据将会达到艾字节。因此,为了适应这种数据规模,我们不得不重新考虑许多东西。
Presto则是其中之一,除了提高查询速度,在CPU使用效率上,这个引擎比Hive高效7倍。另外一个正在进行的项目是缩减Facebook数据中心的分析数据空间。

利用hdfs搭建网盘–webserver开发

利用hdfs搭建网盘–webserver开发,描述下实现思路:
1、网盘系统中的webserver是用来给用户提供操作界面,接收用户指令,完成文件上传、下载、图片上传、下载和图片预览功能的。
2、其中关于存储相关的功能都是调用hdfs API来完成,而关于文件的相关结构化信息都存储在mysql关系型数据库中;
3、webserver起到的是连接客户和hdfs的作用
4、采用的是SSH框架(Struts2、spring、hibernate)、数据库为mysql,数据模型请参考:利用hdfs搭建网盘–数据模型设计
5、web调用hdfs API的思路是:利用java运行时 运行java jar包,可参考《利用HDFS java API增删改查操作》,例如:

process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar read "+fileInfo.getFilePath()+" /root/file-tmp/"+fileInfo.getFileName());

文件列表页面:

@Action(value = "right", results = { @Result(name = "success", location = "/WEB-INF/npage/right.jsp") })
	public String right() {
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		if (user != null) {
			page = fileInfoServie.queryUserFileList(0, 20, user.getUserId());
		}
		return "success";
	}

文件下载:

@Action(value = "downloadFile", results = { @Result(name = "success", location = "/right", type = "redirectAction") })
	public String downloadFile(){
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		//查出要删除的文件信息
		String fileId = getRequest().getParameter("fileId");
		List<FileInfo> lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		//路径
		String path = "/root/file-tmp/"+fileInfo.getFileName();
		// 从hdfs取得文件
		Process process;
		try {
			process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar read "+fileInfo.getFilePath()+" /root/file-tmp/"+fileInfo.getFileName());
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		 try {
            // path是指欲下载的文件的路径。
            File file = new File(path);
            // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            this.getResponse().reset();
            // 设置response的Header
            this.getResponse().addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            this.getResponse().addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(this.getResponse().getOutputStream());
            this.getResponse().setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
	        } catch (IOException ex) {
	            ex.printStackTrace();
	        }
		return null;
	}

删除文件:

@Action(value = "deleteFile", results = { @Result(name = "success", location = "/right", type = "redirectAction") })
	public String deleteFile(){
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		//查出要删除的文件信息
		String fileId = getRequest().getParameter("fileId");
		List<FileInfo> lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		// 将文件从hadoop集群删除
		Process process;
		try {
			process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar delete "+fileInfo.getFilePath());
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//从数据库删除
		fileInfoServie.deleteById(fileInfo.getId());
		return "success";
	}

照片列表:

@Action(value = "goPicPage", results = { @Result(name = "success", location = "/WEB-INF/npage/pic-right.jsp") })
	public String goPicPage() {
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		if (user != null) {
			page = fileInfoServie.queryPicFileList(0, 20, user.getUserId());
		}
		return "success";
	}

上传文件或者图片:

@Action(value = "uploadFile", results = { @Result(name = "success", location = "/right", type = "redirectAction") })
	public String uploadFile() throws IOException {
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		boolean isPic = false;
		if (file_name.indexOf(".jpg") > 0 || file_name.indexOf(".gif") > 0) {
			isPic = true;
		}
		// 接收文件
		String path = "";
		if (null != file_name && !file_name.equals("")) {
			path = fileInfoServie.saveFile(methodFile, file_name);
		}
		String fileName = "";
		String[] strArr = path.split("/");
		if (strArr != null && strArr.length > 0) {
			fileName = strArr[strArr.length - 1];
		}
		// 将文件上传到hadoop集群
		Process process;
		try {
			process = Runtime.getRuntime().exec(
					"java -jar /root/hdfs-0.0.1-SNAPSHOT.jar upload " + path + " hdfs://hadoopm:9000/user/root/upload/"
							+ user.getUserName() + "/" + fileName);
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		FileInfo fileInfo = new FileInfo();
		fileInfo.setCreateTime(new Date());
		fileInfo.setFileName(this.file_name);
		fileInfo.setFilePath("hdfs://hadoopm:9000/user/root/upload/" + user.getUserName() + "/" + fileName);
		File fileTemp = new File(path);
		fileInfo.setFileSize((fileTemp.length() / 1024) > 1 ? (fileTemp.length() / 1024) : 1);
		//判断是否为图片
		if (isPic) {
			fileInfo.setFileType(1);// 0 :普通文件 1:图片
			String tempPath = "/root/" + user.getUserName() + "/"+ System.currentTimeMillis() + "/" + this.file_name;
			ImageScale.resizeFix(new File(path),new File(tempPath), 250, 250);
			fileInfo.setImg(tempPath);
		} else {
			fileInfo.setFileType(0);
		}
		fileInfo.setUserId(user.getUserId());
		fileInfo.setFpos(null);
		fileInfo.setFileId(System.currentTimeMillis());
		fileInfoServie.save(fileInfo);
		return "success";
	}

获取缩略图:

@Action(value = "getsImg")
	public String getsImg() throws IOException {
		String fileId = getRequest().getParameter("fileId");
		List<FileInfo> lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		FileInputStream is = new FileInputStream(fileInfo.getImg());
		int i = is.available(); // 得到文件大小
		byte data[] = new byte[i];
		is.read(data); // 读数据
		is.close();
		this.getResponse().setContentType("image/*"); // 设置返回的文件类型
		OutputStream toClient = this.getResponse().getOutputStream(); // 得到向客户端输出二进制数据的对象
		toClient.write(data); // 输出数据
		toClient.close();
		return null;
	}

获取大图:

@Action(value = "getbImg")
	public String getbImg() throws IOException{
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		//查出要删除的文件信息
		String fileId = getRequest().getParameter("fileId");
		List<FileInfo> lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		//路径
		String path = "/root/file-tmp/bpic/"+fileInfo.getFileName();
		// 从hdfs取得文件
		Process process;
		try {
			process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar read "+fileInfo.getFilePath()+" /root/file-tmp/bpic/"+fileInfo.getFileName());
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		File f = new File(path);
        if (!f.exists()) {
            this.getResponse().sendError(404, "File not found!");
            return null;
        }
        BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));
        byte[] buf = new byte[1024];
        int len = 0;
        this.getResponse().reset(); // 非常重要
        // 在线打开方式
        URL u = new URL("file:///" + path);
        this.getResponse().setContentType(u.openConnection().getContentType());
        this.getResponse().setHeader("Content-Disposition", "inline; filename=" + f.getName());
        // 文件名应该编码成UTF-8
        OutputStream out = this.getResponse().getOutputStream();
        while ((len = br.read(buf)) > 0)
            out.write(buf, 0, len);
        br.close();
        out.close();
		return null;
	}

完整Action类如下:

package org.nbc.storage.file.action;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.nbc.storage.common.action.BaseAction;
import org.nbc.storage.common.util.ImageScale;
import org.nbc.storage.file.model.FileInfo;
import org.nbc.storage.file.service.FileInfoServie;
import org.nbc.storage.user.model.User;
import com.sitech.core.orm.PropertyFilter;
import com.sitech.core.utils.Page;
public class FileAction extends BaseAction {
	private static final long serialVersionUID = 1L;
	private Page page;
	private String file_name;
	private File methodFile;
	/** 下载需要的 */
	private InputStream inputStream;
	private String downloadFileName;
	@Resource
	public FileInfoServie fileInfoServie;
	@Action(value = "files", results = { @Result(name = "success", location = "/WEB-INF/npage/main.jsp") })
	public String userFileList() {
		return "success";
	}
	@Action(value = "top", results = { @Result(name = "success", location = "/WEB-INF/npage/top.jsp") })
	public String top() {
		return "success";
	}
	@Action(value = "left", results = { @Result(name = "success", location = "/WEB-INF/npage/left.jsp") })
	public String left() {
		return "success";
	}
	@Action(value = "right_top", results = { @Result(name = "success", location = "/WEB-INF/npage/right_top.jsp") })
	public String right_top() {
		return "success";
	}
	@Action(value = "right", results = { @Result(name = "success", location = "/WEB-INF/npage/right.jsp") })
	public String right() {
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		if (user != null) {
			page = fileInfoServie.queryUserFileList(0, 20, user.getUserId());
		}
		return "success";
	}
	/**
	 *
	 * 下载文件.
	 *
	 * @return
	 */
	@Action(value = "downloadFile", results = { @Result(name = "success", location = "/right", type = "redirectAction") })
	public String downloadFile(){
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		//查出要删除的文件信息
		String fileId = getRequest().getParameter("fileId");
		List lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		//路径
		String path = "/root/file-tmp/"+fileInfo.getFileName();
		// 从hdfs取得文件
		Process process;
		try {
			process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar read "+fileInfo.getFilePath()+" /root/file-tmp/"+fileInfo.getFileName());
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		 try {
            // path是指欲下载的文件的路径。
            File file = new File(path);
            // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            this.getResponse().reset();
            // 设置response的Header
            this.getResponse().addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            this.getResponse().addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(this.getResponse().getOutputStream());
            this.getResponse().setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
	        } catch (IOException ex) {
	            ex.printStackTrace();
	        }
		return null;
	}
	/**
	 *
	 * 删除文件.
	 *
	 * @return
	 */
	@Action(value = "deleteFile", results = { @Result(name = "success", location = "/right", type = "redirectAction") })
	public String deleteFile(){
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		//查出要删除的文件信息
		String fileId = getRequest().getParameter("fileId");
		List lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		// 将文件从hadoop集群删除
		Process process;
		try {
			process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar delete "+fileInfo.getFilePath());
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//从数据库删除
		fileInfoServie.deleteById(fileInfo.getId());
		return "success";
	}
	@Action(value = "goUploadPage", results = { @Result(name = "success", location = "/WEB-INF/npage/upload-right.jsp") })
	public String goUploadPage() {
		return "success";
	}
	@Action(value = "goPicPage", results = { @Result(name = "success", location = "/WEB-INF/npage/pic-right.jsp") })
	public String goPicPage() {
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		if (user != null) {
			page = fileInfoServie.queryPicFileList(0, 20, user.getUserId());
		}
		return "success";
	}
	/**
	 *
	 * 上传文件或图片.
	 *
	 * @return
	 * @throws IOException
	 */
	@Action(value = "uploadFile", results = { @Result(name = "success", location = "/right", type = "redirectAction") })
	public String uploadFile() throws IOException {
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		boolean isPic = false;
		if (file_name.indexOf(".jpg") > 0 || file_name.indexOf(".gif") > 0) {
			isPic = true;
		}
		// 接收文件
		String path = "";
		if (null != file_name && !file_name.equals("")) {
			path = fileInfoServie.saveFile(methodFile, file_name);
		}
		String fileName = "";
		String[] strArr = path.split("/");
		if (strArr != null && strArr.length > 0) {
			fileName = strArr[strArr.length - 1];
		}
		// 将文件上传到hadoop集群
		Process process;
		try {
			process = Runtime.getRuntime().exec(
					"java -jar /root/hdfs-0.0.1-SNAPSHOT.jar upload " + path + " hdfs://hadoopm:9000/user/root/upload/"
							+ user.getUserName() + "/" + fileName);
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		FileInfo fileInfo = new FileInfo();
		fileInfo.setCreateTime(new Date());
		fileInfo.setFileName(this.file_name);
		fileInfo.setFilePath("hdfs://hadoopm:9000/user/root/upload/" + user.getUserName() + "/" + fileName);
		File fileTemp = new File(path);
		fileInfo.setFileSize((fileTemp.length() / 1024) > 1 ? (fileTemp.length() / 1024) : 1);
		//判断是否为图片
		if (isPic) {
			fileInfo.setFileType(1);// 0 :普通文件 1:图片
			String tempPath = "/root/" + user.getUserName() + "/"+ System.currentTimeMillis() + "/" + this.file_name;
			ImageScale.resizeFix(new File(path),new File(tempPath), 250, 250);
			fileInfo.setImg(tempPath);
		} else {
			fileInfo.setFileType(0);
		}
		fileInfo.setUserId(user.getUserId());
		fileInfo.setFpos(null);
		fileInfo.setFileId(System.currentTimeMillis());
		fileInfoServie.save(fileInfo);
		return "success";
	}
	/**
	 *
	 * 获取缩略图.
	 *
	 * @return
	 * @throws IOException
	 */
	@Action(value = "getsImg")
	public String getsImg() throws IOException {
		String fileId = getRequest().getParameter("fileId");
		List lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		FileInputStream is = new FileInputStream(fileInfo.getImg());
		int i = is.available(); // 得到文件大小
		byte data[] = new byte[i];
		is.read(data); // 读数据
		is.close();
		this.getResponse().setContentType("image/*"); // 设置返回的文件类型
		OutputStream toClient = this.getResponse().getOutputStream(); // 得到向客户端输出二进制数据的对象
		toClient.write(data); // 输出数据
		toClient.close();
		return null;
	}
	/**
	 *
	 * 获取大图.
	 *
	 * @return
	 * @throws IOException
	 */
	@Action(value = "getbImg")
	public String getbImg() throws IOException{
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		//查出要删除的文件信息
		String fileId = getRequest().getParameter("fileId");
		List lists = fileInfoServie.findBy("fileId", Long.parseLong(fileId), PropertyFilter.MatchType.EQ);
		FileInfo fileInfo = new FileInfo();
		if(lists != null && lists.size() > 0){
			fileInfo = lists.get(0);
		}
		//路径
		String path = "/root/file-tmp/bpic/"+fileInfo.getFileName();
		// 从hdfs取得文件
		Process process;
		try {
			process = Runtime.getRuntime().exec("java -jar /root/hdfs-0.0.1-SNAPSHOT.jar read "+fileInfo.getFilePath()+" /root/file-tmp/bpic/"+fileInfo.getFileName());
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		File f = new File(path);
        if (!f.exists()) {
            this.getResponse().sendError(404, "File not found!");
            return null;
        }
        BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));
        byte[] buf = new byte[1024];
        int len = 0;
        this.getResponse().reset(); // 非常重要
        // 在线打开方式
        URL u = new URL("file:///" + path);
        this.getResponse().setContentType(u.openConnection().getContentType());
        this.getResponse().setHeader("Content-Disposition", "inline; filename=" + f.getName());
        // 文件名应该编码成UTF-8
        OutputStream out = this.getResponse().getOutputStream();
        while ((len = br.read(buf)) > 0)
            out.write(buf, 0, len);
        br.close();
        out.close();
		return null;
	}
	public FileInfoServie getFileInfoServie() {
		return fileInfoServie;
	}
	public void setFileInfoServie(FileInfoServie fileInfoServie) {
		this.fileInfoServie = fileInfoServie;
	}
	public Page getPage() {
		return page;
	}
	public void setPage(Page page) {
		this.page = page;
	}
	public String getFile_name() {
		return file_name;
	}
	public void setFile_name(String file_name) {
		this.file_name = file_name;
	}
	public File getMethodFile() {
		return methodFile;
	}
	public void setMethodFile(File methodFile) {
		this.methodFile = methodFile;
	}
	public String getDownloadFileName() {
		return downloadFileName;
	}
	public void setDownloadFileName(String downloadFileName) {
		this.downloadFileName = downloadFileName;
	}
	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}
	@Action(value = "filelist", results = { @Result(name = "success", location = "/WEB-INF/npage/filelist.jsp") })
	public String filelist() {
//		HttpSession session = this.getRequest().getSession();
//		User user = (User) session.getAttribute("user");
//		if (user != null) {
			page = fileInfoServie.queryUserFileList(0, 20, 1L);
//		}
		return "success";
	}
	@Action(value = "goUploadPageCC", results = { @Result(name = "success", location = "/WEB-INF/npage/goUploadPageCC.jsp") })
	public String goUploadPageCC() {
		return "success";
	}
	@Action(value = "uploadFileCC", results = { @Result(name = "success", location = "/filelist", type = "redirectAction") })
	public String uploadFileCC() throws IOException {
		// 获取用户信息
		HttpSession session = this.getRequest().getSession();
		User user = (User) session.getAttribute("user");
		boolean isPic = false;
		if (file_name.indexOf(".jpg") > 0 || file_name.indexOf(".gif") > 0) {
			isPic = true;
		}
		// 接收文件
		String path = "";
		if (null != file_name && !file_name.equals("")) {
			path = fileInfoServie.saveFile(methodFile, file_name);
		}
		String fileName = "";
		String[] strArr = path.split("/");
		if (strArr != null && strArr.length > 0) {
			fileName = strArr[strArr.length - 1];
		}
		// 将文件上传到hadoop集群
		Process process;
		try {
			process = Runtime.getRuntime().exec(
					"java -jar /root/hdfs-0.0.1-SNAPSHOT.jar upload " + path + " hdfs://hadoopm:9000/user/root/upload/"
							+ "lisn" + "/" + fileName);
			InputStreamReader ir = new InputStreamReader(process.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line;
			while ((line = input.readLine()) != null)
				System.out.println(line);
		} catch (IOException e) {
			e.printStackTrace();
		}
		FileInfo fileInfo = new FileInfo();
		fileInfo.setCreateTime(new Date());
		fileInfo.setFileName(this.file_name);
		fileInfo.setFilePath("hdfs://hadoopm:9000/user/root/upload/" +"lisn" + "/" + fileName);
		File fileTemp = new File(path);
		fileInfo.setFileSize((fileTemp.length() / 1024) > 1 ? (fileTemp.length() / 1024) : 1);
		//判断是否为图片
		if (isPic) {
			fileInfo.setFileType(1);// 0 :普通文件 1:图片
			String tempPath = "/root/" + "lisn" + "/"+ System.currentTimeMillis() + "/" + this.file_name;
			ImageScale.resizeFix(new File(path),new File(tempPath), 250, 250);
			fileInfo.setImg(tempPath);
		} else {
			fileInfo.setFileType(0);
		}
		fileInfo.setUserId(1L);
		fileInfo.setFpos(null);
		fileInfo.setFileId(System.currentTimeMillis());
		fileInfoServie.save(fileInfo);
		return "success";
	}
}

完整services:

package org.nbc.storage.file.service.impl;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import javax.annotation.Resource;
import org.nbc.storage.file.model.FileInfo;
import org.nbc.storage.file.service.FileInfoServie;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sitech.core.orm.BaseDAO;
import com.sitech.core.service.impl.BaseServiceImpl;
import com.sitech.core.utils.Page;
@Service("fileInfoServie")
@Transactional
public class FileInfoServieImpl extends BaseServiceImpl<FileInfo, Long> implements FileInfoServie {
	private static int BUFFER_SIZE = 16 * 1024;
	@Resource(name = "fileInfoDAO")
	public void setBaseDAO(BaseDAO<FileInfo, Long> baseDAO) {
		super.setBaseDAO(baseDAO);
	}
	@Override
	public Page<FileInfo> queryUserFileList(int pageNo,
			int pageSize, Long userId) {
		String hql = " from FileInfo where userId = ? order by createTime desc ";
		Page<FileInfo> page = new Page<FileInfo>(pageSize);
		page.setPageNo(pageNo);
		return this.getBaseDAO().findPage(page, hql, userId);
	}
	public long copyFile(File src, File dest) throws Exception {
		BufferedInputStream in = null;
		BufferedOutputStream out = null;
		byte[] buffer = new byte[BUFFER_SIZE];
		long total = 0;
		try {
			in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE);
			out = new BufferedOutputStream(new FileOutputStream(dest),
					BUFFER_SIZE);
			int curSize = in.read(buffer);
			while (curSize > 0) {
				total += curSize;
				out.write(buffer, 0, curSize);
				curSize = in.read(buffer);
			}
		} catch (Exception e) {
		} finally {
			try {
				if (in != null) {
					in.close();
					in = null;
				}
				if (out != null) {
					out.close();
					out = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return total;
	}
	public String saveFile(File methodFile,String file_name){
		String savePath = "/root/lisn/";
		String middlePath = "";
		String separator = "/";
		String [] strArr = file_name.split("\.");
		if(strArr != null && strArr.length > 0){
			file_name = strArr[strArr.length-1];
		}
		//创建filename
		file_name = System.currentTimeMillis() + "."+file_name;
		File f = new File(savePath);
		if (!f.exists()) {
			f.mkdirs();
		}
		File file = new File(savePath+file_name);
		try {
			file.createNewFile();
			long total = copyFile(methodFile, file);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return savePath+file_name;
	}
	@Override
	public Page<FileInfo> queryPicFileList(int pageNo, int pageSize, Long userId) {
		String hql = " from FileInfo where userId = ? and fileType = 1 order by createTime desc ";
		Page<FileInfo> page = new Page<FileInfo>(pageSize);
		page.setPageNo(pageNo);
		return this.getBaseDAO().findPage(page, hql, userId);
	}
}

展示图片预览页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
<!--
.STYLE1 {font-size: 12px}
.STYLE3 {color: #707070; font-size: 12px; }
.STYLE5 {color: #0a6e0c; font-size: 12px; }
body {
	margin-top: 0px;
	margin-bottom: 0px;
}
.STYLE7 {font-size: 12}
-->
</style>
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
  <tr>
    <td height="30"><table width="100%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td>&nbsp;</td>
        <td style="padding-right:10px;"><div align="right">
          <table border="0" align="right" cellpadding="0" cellspacing="0">
            <tr>
              <td width="60"><table width="87%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                   <!--  <td class="STYLE1"><div align="center">
                        <input type="checkbox" name="checkbox62" value="checkbox" />
                    </div></td>-->
                    <td class="STYLE1" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/goPicPage'"><div align="center" style="cursor:pointer;">图片列表</div></td>
                  </tr>
              </table></td>
              <td width="60"><table width="90%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                  <!--   <td class="STYLE1"><div align="center"><img src="<%=request.getContextPath() %>/images/001.gif" width="14" height="14" /></div></td> -->
                    <td class="STYLE1" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/goUploadPage'"><div align="center" style="cursor:pointer;">上传文件</div></td>
                  </tr>
              </table></td>
              <td width="60"><table width="90%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                   <!--  <td class="STYLE1"><div align="center"><img src="<%=request.getContextPath() %>/images/114.gif" width="14" height="14" /></div></td> -->
                    <td class="STYLE1" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/right'"><div align="center" style="cursor:pointer;">文件列表</div></td>
                  </tr>
              </table></td>
              <!--
              <td width="52"><table width="88%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                    <td class="STYLE1"><div align="center"><img src="<%=request.getContextPath() %>/images/083.gif" width="14" height="14" /></div></td>
                    <td class="STYLE1"><div align="center">删除</div></td>
                  </tr>
              </table></td>
               -->
            </tr>
          </table>
        </div></td>
      </tr>
    </table></td>
  </tr>
  <tr>
    <td><table width="100%" border="0" cellpadding="0" cellspacing="1" bgcolor="#c9c9c9">
      <tr>
        <td height="22" bgcolor="#FFFFFF" width="50%"><div align="center"><strong><span class="STYLE1">图片预览</span></strong></div></td>
      </tr>
      <s:iterator value="page.result" var="file">
      <tr>
        <td height="22" bgcolor="#FFFFFF" width="50%"><div align="center"><span class="STYLE3" style="cursor:pointer;"><img onclick="window.open('http://192.168.75.142:8080/wangpan-web/getbImg?fileId=<s:property value="fileId" />');" title="点击查看大图" alt="<s:property value="fileName" />" src="http://192.168.75.142:8080/wangpan-web/getsImg?fileId=<s:property value="fileId" />" >  </span></div></td>
      </tr>
      </s:iterator>
    </table></td>
  </tr>
  <tr>
    <td height="35"><table width="100%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td width="25%" height="29" nowrap="nowrap"><table width="342" border="0" cellspacing="0" cellpadding="0">
          <tr>
            <td width="44%" class="STYLE1">当前页:1/2页 每页
              <input name="textfield2" type="text" class="STYLE1" style="height:14px; width:25px;" value="15" size="5" />            </td>
            <td width="14%" class="STYLE1"><img src="<%=request.getContextPath() %>/images/sz.gif" width="43" height="20" /></td>
            <td width="42%" class="STYLE1"><span class="STYLE7">数据总量 15 </span></td>
          </tr>
        </table></td>
        <td width="75%" valign="top" class="STYLE1"><div align="right">
            <table width="352" height="20" border="0" cellpadding="0" cellspacing="0">
              <tr>
                <td width="62" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_first_1.gif" width="48" height="20" /></div></td>
                <td width="50" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_back_1.gif" width="55" height="20" /></div></td>
                <td width="54" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_next.gif" width="58" height="20" /></div></td>
                <td width="49" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_last.gif" width="52" height="20" /></div></td>
                <td width="59" height="22" valign="middle"><div align="right">转到第</div></td>
                <td width="25" height="22" valign="middle"><span class="STYLE7">
                  <input name="textfield" type="text" class="STYLE1" style="height:10px; width:25px;" size="5" />
                </span></td>
                <td width="23" height="22" valign="middle">页</td>
                <td width="30" height="22" valign="middle"><img src="<%=request.getContextPath() %>/images/go.gif" width="26" height="20" /></td>
              </tr>
            </table>
        </div></td>
      </tr>
    </table></td>
  </tr>
</table>
</body>
</html>

文件列表页:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
<!--
.STYLE1 {font-size: 12px}
.STYLE3 {color: #707070; font-size: 12px; }
.STYLE5 {color: #0a6e0c; font-size: 12px; }
body {
	margin-top: 0px;
	margin-bottom: 0px;
}
.STYLE7 {font-size: 12}
-->
</style>
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
  <tr>
    <td height="30"><table width="100%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td>&nbsp;</td>
        <td style="padding-right:10px;"><div align="right">
          <table border="0" align="right" cellpadding="0" cellspacing="0">
            <tr>
              <td width="60"><table width="87%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                   <!--  <td class="STYLE1"><div align="center">
                        <input type="checkbox" name="checkbox62" value="checkbox" />
                    </div></td>-->
                    <td class="STYLE1" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/goPicPage'"><div align="center" style="cursor:pointer;">图片列表</div></td>
                  </tr>
              </table></td>
              <td width="60"><table width="90%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                  <!--   <td class="STYLE1"><div align="center"><img src="<%=request.getContextPath() %>/images/001.gif" width="14" height="14" /></div></td> -->
                    <td class="STYLE1" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/goUploadPage'"><div align="center" style="cursor:pointer;">上传文件</div></td>
                  </tr>
              </table></td>
              <td width="60"><table width="90%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                   <!--  <td class="STYLE1"><div align="center"><img src="<%=request.getContextPath() %>/images/114.gif" width="14" height="14" /></div></td> -->
                    <td class="STYLE1" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/right'"><div align="center" style="cursor:pointer;">文件列表</div></td>
                  </tr>
              </table></td>
              <!--
              <td width="52"><table width="88%" border="0" cellpadding="0" cellspacing="0">
                  <tr>
                    <td class="STYLE1"><div align="center"><img src="<%=request.getContextPath() %>/images/083.gif" width="14" height="14" /></div></td>
                    <td class="STYLE1"><div align="center">删除</div></td>
                  </tr>
              </table></td>
               -->
            </tr>
          </table>
        </div></td>
      </tr>
    </table></td>
  </tr>
  <tr>
    <td><table width="100%" border="0" cellpadding="0" cellspacing="1" bgcolor="#c9c9c9">
      <tr>
        <td height="22" bgcolor="#FFFFFF" width="50%"><div align="center"><strong><span class="STYLE1">文件名</span></strong></div></td>
        <td height="22" bgcolor="#FFFFFF"><div align="center"><strong><span class="STYLE1">大小</span></strong></div></td>
        <td height="22" bgcolor="#FFFFFF"><div align="center"><strong><span class="STYLE1">上传日期</span></strong></div></td>
        <td height="22" bgcolor="#FFFFFF"><div align="center"><strong><span class="STYLE1">操作</span></strong></div></td>
      </tr>
      <s:iterator value="page.result" var="file">
      <tr>
        <td height="22" bgcolor="#FFFFFF" width="50%"><div align="center"><span class="STYLE3"><s:property value="fileName" /></span></div></td>
        <td height="22" bgcolor="#FFFFFF"><div align="center"><span class="STYLE3"><s:property value="fileSize" />&nbsp;KB</span></div></td>
        <td height="22" bgcolor="#FFFFFF"><div align="center"><span class="STYLE3"><s:date name="createTime" format="yyyy-MM-dd HH:mm" /></span></div></td>
        <td height="22" bgcolor="#FFFFFF">
        	<div align="center">
        		<span style="cursor:pointer;" class="STYLE3" onclick="window.location.href='<%=request.getContextPath() %>/wangpan-web/deleteFile?fileId=<s:property value="fileId" />'">删除</span>
        		<span style="cursor:pointer;" class="STYLE3" onclick="window.open('<%=request.getContextPath() %>/wangpan-web/downloadFile?fileId=<s:property value="fileId" />');">下载</span>
        		</div>
        </td>
      </tr>
      </s:iterator>
    </table></td>
  </tr>
  <tr>
    <td height="35"><table width="100%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td width="25%" height="29" nowrap="nowrap"><table width="342" border="0" cellspacing="0" cellpadding="0">
          <tr>
            <td width="44%" class="STYLE1">当前页:1/2页 每页
              <input name="textfield2" type="text" class="STYLE1" style="height:14px; width:25px;" value="15" size="5" />            </td>
            <td width="14%" class="STYLE1"><img src="<%=request.getContextPath() %>/images/sz.gif" width="43" height="20" /></td>
            <td width="42%" class="STYLE1"><span class="STYLE7">数据总量 15 </span></td>
          </tr>
        </table></td>
        <td width="75%" valign="top" class="STYLE1"><div align="right">
            <table width="352" height="20" border="0" cellpadding="0" cellspacing="0">
              <tr>
                <td width="62" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_first_1.gif" width="48" height="20" /></div></td>
                <td width="50" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_back_1.gif" width="55" height="20" /></div></td>
                <td width="54" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_next.gif" width="58" height="20" /></div></td>
                <td width="49" height="22" valign="middle"><div align="right"><img src="<%=request.getContextPath() %>/images/page_last.gif" width="52" height="20" /></div></td>
                <td width="59" height="22" valign="middle"><div align="right">转到第</div></td>
                <td width="25" height="22" valign="middle"><span class="STYLE7">
                  <input name="textfield" type="text" class="STYLE1" style="height:10px; width:25px;" size="5" />
                </span></td>
                <td width="23" height="22" valign="middle">页</td>
                <td width="30" height="22" valign="middle"><img src="<%=request.getContextPath() %>/images/go.gif" width="26" height="20" /></td>
              </tr>
            </table>
        </div></td>
      </tr>
    </table></td>
  </tr>
</table>
</body>
</html>

利用hdfs搭建网盘–数据模型设计

先阐述下利用hdfs搭建网盘的思路:
(1)、首先要搭建hadoop集群,确保该集群正常运行
(2)、通过API访问文件到存储在hdfs中的文件,能对文件进行增删改查
(3)、文件的其他结构化信息,,比如:文件名称,上传时间,所属用户、文件类型等信息,需要存储在数据库里,我们使用mysql
(4)、用户需要通过操作界面来访问网盘系统,而不是直接操作hdfs,这里采用java、struts2框架来实现web端开发
(5)、有用户系统,存储用户相关信息,另外hdfs中文件存放的路径也和用户有直接关系
网盘系统的截图:http://pan.baidu.com/share/link?shareid=3253971941&uk=772112791
第一点已经在《Hadoop集群搭建详细简明教程》里详细写明步骤了,再次就不再提了
第二点已经在《利用HDFS java API增删改查操作》里详细阐述了
这篇文章先阐述下第三、第五点
网盘数据模型的设计,以及mysql在linux下的安装
网盘数据模型的设计:

file_info

file_info


user

user


tables

tables


目前只用到这file_ifno,user这两个表
mysql在linux:
我是在《Hadoop集群搭建详细简明教程》中搭建好的hadoopm主机上,通过yum安装的mysql,并设置mysql密码

yum install mysql
yum install mysql-server
yum install mysql-devel
chgrp -R mysql /var/lib/mysql
chmod -R 770 /var/lib/mysql
service mysqld start
mysql
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('secret_password');

PS:设置密码的时候可能会报错:ERROR 1372 (HY000): Password hash should be a 41-digit hexadecimal number
可通过这个命令:select password(‘root’);得知root的 41-digit是什么
设置mysql开机启动:

chkconfig --levels 345 mysqld on

相关参考资料:
1、linux下安装mysql
2、设置用户
http://www.hackbase.com/tech/2011-09-09/65234.html
yum install mysql
http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/10/16/2214272.html
3、远程连接
http://www.cnblogs.com/smallstone/archive/2010/04/29/1723838.html
4、创建数据库–奇怪的问题:必须得使用特别奇怪的引号,否则不生效
http://tdcq.iteye.com/blog/363955
http://blog.sina.com.cn/s/blog_5dc960cd0100ea2h.html
5、在数据库上创建表
http://www.51cto.com/html/2005/1129/12524.htm
6、mysql中文乱码
http://www.2cto.com/database/201108/101151.html
7、修改表结构
http://database.51cto.com/art/201005/201148.htm
8、2007-07-20 10:59 在mysql中查询一个数据库中的所有表
http://hi.baidu.com/aigyoo/item/d56a8c01dcb50c10cd34eacf
9、mysql查看表结构命令
http://www.blogjava.net/etlan/archive/2007/07/12/129794.html

Hadoop知识整理

按照what、how、why整理了下文章,帮助大家快速梳理下hadoop知识:
what:
Hadoop的作用: http://tianhailong.com/hadoop%E7%9A%84%E4%BD%9C%E7%94%A8.html
hadoop到底能做什么?怎么用hadoop?: http://tianhailong.com/hadoop%E5%88%B0%E5%BA%95%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F%E6%80%8E%E4%B9%88%E7%94%A8hadoop%EF%BC%9F.html
Hadoop和云计算的关系: http://tianhailong.com/hadoop%E5%92%8C%E4%BA%91%E8%AE%A1%E7%AE%97%E7%9A%84%E5%85%B3%E7%B3%BB.html
hadoop和java的关系: http://tianhailong.com/hadoop%E5%92%8Cjava%E7%9A%84%E5%85%B3%E7%B3%BB.html
Hadoop10大应用: http://tianhailong.com/hadoop10%E5%A4%A7%E5%BA%94%E7%94%A8.html
Hadoop是分布式计算的未来: http://tianhailong.com/187.html
Hadoop发展历史: http://tianhailong.com/hadoop%E5%8F%91%E5%B1%95%E5%8E%86%E5%8F%B2.html
Hadoop大事记: http://tianhailong.com/hadoop%E5%A4%A7%E4%BA%8B%E8%AE%B0.html
Hadoop主要子项目: http://tianhailong.com/hadoop%E4%B8%BB%E8%A6%81%E5%AD%90%E9%A1%B9%E7%9B%AE.html
Hadoop, Hive和Scribe在运维方面的应用: http://tianhailong.com/hadoop-hive%E5%92%8Cscribe%E5%9C%A8%E8%BF%90%E7%BB%B4%E6%96%B9%E9%9D%A2%E7%9A%84%E5%BA%94%E7%94%A8.html
hadoop招聘: http://tianhailong.com/hadoop%E6%8B%9B%E8%81%98.html
how:
渐进学习hadoop: http://tianhailong.com/%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0hadoop.html
hadoop基础-Hadoop入门一: http://tianhailong.com/hadoop%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86%E7%82%B9.html
认识hdfs和MapReduce-Hadoop入门二: http://tianhailong.com/hadoop%E5%85%A5%E9%97%A8%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86%E7%82%B9%E4%BA%8C.html
HDFS开发MapReduce开发-Hadoop入门三: http://tianhailong.com/hadoop%E5%85%A5%E9%97%A8%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86%E7%82%B9%E4%B8%89.html
hadoop在百度的应用: http://tianhailong.com/hadoop%E5%9C%A8%E7%99%BE%E5%BA%A6%E7%9A%84%E5%BA%94%E7%94%A8.html
Hadoop集群搭建–Hadoop安装: http://tianhailong.com/hadoop%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BAhadoop%E5%AE%89%E8%A3%85.html
why:
hdfs:hadoop分布式文件系统的架构和设计: http://tianhailong.com/hdfs%EF%BC%9Ahadoop%E5%88%86%E5%B8%83%E5%BC%8F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%9E%B6%E6%9E%84%E5%92%8C%E8%AE%BE%E8%AE%A1.html

利用HDFS java API增删改查操作

利用HDFS java API增删改查操作
在做这个实验的时候需要特别注意下面三个问题:
1、hdfs安全模式需要关闭 命令:./hadoop dfsadmin -safemode leave
2、工程中依赖的版本必须和集群的一致,否则也会报 version不一致错误
3、hadoop集群用户权限的问题,以及各个目录的作用
目前为什么会有这三个问题的原因待查!!!
未验证目前使用hadoop的版本(release-0.20.0)是否支持webhdfs,反正我是怎么都连接不上啊!!!
从这上面看,0.20.0 可能是不支持的
https://jira.springsource.org/browse/IMPALA-15?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
Serengeti Distro:
Apache Hadoop:1.0.1
GreenPlum HD:1.1(Apache Hadoop 1.0.0)
CloudEra: CDH3(Apache Hadoop 0.20.2, WebHDFS is not supported in this version)
Hortonworks: 1.0.7 (Apache Hadoop 1.0.2)
步骤如下:
工程结构,如图:

工程结构

工程结构


上代码 O(∩_∩)O哈哈~
pom.xml配置如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.yun.hdfs</groupId>
	<artifactId>hdfs</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<configuration>
					<appendAssemblyId>false</appendAssemblyId>
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					</descriptorRefs>
					<archive>
						<manifest>
							<mainClass>com.yun.hdfs.WangPan</mainClass>
						</manifest>
					</archive>
				</configuration>
				<executions>
					<execution>
						<id>make-assembly</id>
						<phase>package</phase>
						<goals>
							<goal>assembly</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-core</artifactId>
			<version>0.20.2</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
	</dependencies>
</project>

WangPan.java 主方法用于调用:

package com.yun.hdfs;
import java.io.IOException;
public class WangPan {
	/*** 运行结果描述. */
	private static String result = "";
	public static void main(String[] args) {
		try {
			// 判断命令输入是否正确
			if (args[0] != null && !"".equals(args[0]) && args.length > 0) {
				if ("upload".equals(args[0])) {
					result = "upload:" + WangPanUtils.uploadFile(args);
				} else if ("delete".equals(args[0])) {
					result = "delete:" + WangPanUtils.deleteFile(args);
				} else if ("query".equals(args[0])) {
					if (WangPanUtils.listFile(args) == null) {
						result = "query:fail!";
					} else {
						result = "query:success";
					}
				} else if ("read".equals(args[0])) {
					result = "read:" + WangPanUtils.readFile(args);
				} else {
					System.out.println("sorry,wo have no this service!");
				}
				System.out.println(result);
			} else {
				System.out.println("fail!");
				System.exit(1);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

WangPanUtils.java增删改查:

package com.yun.hdfs;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
public class WangPanUtils {
	/**
	 * 上传文件. java -jar /root/hdfs-0.0.1-SNAPSHOT.jar upload /root/test-hdfs.txt
	 * hdfs://hadoopm:9000/user/root/upload/12390po.txt
	 *
	 * @param args
	 * @return
	 * @throws IOException
	 */
	public static String uploadFile(String[] args) throws IOException {
		String loaclSrc = args[1];
		String dst = args[2];
		if (args.length < 3) {
			return "fail";
		}
		InputStream in = new BufferedInputStream(new FileInputStream(loaclSrc));
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(dst), conf);
		OutputStream out = fs.create(new Path(dst));
		IOUtils.copyBytes(in, out, 4096, true);
		return "success";
	}
	/**
	 * 查询文件列表. java -jar /root/hdfs-0.0.1-SNAPSHOT.jar query
	 * hdfs://hadoopm:9000/user/root/
	 *
	 * @param args
	 * @return
	 * @throws IOException
	 */
	public static Path[] listFile(String[] args) throws IOException {
		if (args.length < 2) {
			return null;
		}
		String dst = args[1];
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(dst), conf);
		FileStatus[] statu = fs.listStatus(new Path(dst));
		Path[] listPaths = FileUtil.stat2Paths(statu);
		return listPaths;
	}
	/**
	 * 删除文件.
	 * java -jar /root/hdfs-0.0.1-SNAPSHOT.jar delete hdfs://hadoopm:9000/user/root/upload/12390po.txt
	 *
	 * @param args
	 * @return
	 * @throws IOException
	 */
	public static String deleteFile(String[] args) throws IOException {
		if (args.length < 2) {
			return "fail";
		}
		String fileName = args[1];
		Configuration config = new Configuration();
		FileSystem hdfs = FileSystem.get(URI.create(fileName), config);
		Path path = new Path(fileName);
		if (!hdfs.exists(path)) {
			return "fail";
		}
		boolean isDeleted = hdfs.delete(path, false);
		if (isDeleted) {
			return "success";
		} else {
			return "fail";
		}
	}
	/**
	 * 读取文件.
	 * java -jar /root/hdfs-0.0.1-SNAPSHOT.jar read hdfs://hadoopm:9000/user/root/upload/123.txt /root/test-readfile898.txt
	 *
	 * @param args
	 * @return
	 * @throws IOException
	 */
	public static String readFile(String[] args) throws IOException {
		if(args.length < 3){
			return "fail";
		}
		String dst = args[1];
		String newPath = args[2];
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(dst), conf);
		FSDataInputStream hdfsInStream = fs.open(new Path(dst));
		OutputStream out = new FileOutputStream(newPath);
		byte[] ioBuffer = new byte[1024];
		int readLen = hdfsInStream.read(ioBuffer);
		while (-1 != readLen) {
			out.write(ioBuffer, 0, readLen);
			readLen = hdfsInStream.read(ioBuffer);
		}
		out.close();
		hdfsInStream.close();
		fs.close();
		return "success";
	}
}
/**
	 * 创建文件夹.
	 * java -jar /root/hdfs-0.0.1-SNAPSHOT.jar mkdir hdfs://hadoopm:9000/user/root/upload/test909
	 *
	 * @return
	 * @throws IOException
	 */
	public static String mkdir(String[] args) throws IOException{
		if(args.length < 2){
			return "fali";
		}
		String dst = args[1];
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(URI.create(dst), conf);
		Path path = new Path(dst);
		if (fs.exists(path)) {
			return "fail";
		}
		fs.mkdirs(path);
		return "success";
	}

PS:需要注意的是,我们需要把这个工程利用maven打包成一个可运行的jar包,使用如下命令:

打包命令

打包命令


执行命令在每个方法注释上写明了,执行效果如下:
增删改查效果

增删改查效果


还需要访问 http://hadoopm:50070/ -> Browse the filesystem 查看hdfs文件操作是否真的成功
web hdfs

web hdfs