import java.io.IOException;
import
java.io.InputStream;
import
java.net.URI;
import
org.apache.hadoop.conf.Configuration;
import
org.apache.hadoop.fs.FileSystem;
import
org.apache.hadoop.fs.Path;
import
org.apache.hadoop.io.IOUtils;
public
class
FileSystemCat {
/**
*
@param
args
*
@throws
IOException
*/
public
static
void
main(String[] args)
throws
IOException {
//
TODO
Auto-generated method stub
String uri = args[0];
Configuration conf =
new
Configuration();//获得系统的配置信息
FileSystem fs = FileSystem.get(URI.create(uri),conf);//打开Hadoop要使用的文件系统
InputStream in =
null
;
try
{
in = fs.open(
new
Path(uri));//fs open 获得的是文件的InputStream流 其实open()方法返回的是FSDataInputStream对象,而不是标准的java.io类对象,这个类是继承了java.io.DataInputStream接口的一个特殊类。
IOUtils.copyBytes(in, System.
out
,4096,
false
);
}
finally
{
IOUtils.closeStream(in);
}
}
}
hadoop jar /home/lilin/Desktop/FileSystemCat.jar FileSystemCat hdfs://namenode:9000/usr/lilin/test 运行jar包只能运行jar里边的一个类
FileStatus类封装了文件系统中文件盒目录的元数据,包括文件长度,块大小,备份,修改时间,所有者以及权限信息
FileSystem的getFileStatus()方法用于获取文件或者目录的FileStatus对象
Path[] paths = new Path[args.length];
for (int i = 0; i < paths.length; i++) {
paths[i] = new Path(args[i]);
}
FileStatus[] status = fs.listStatus(paths);
Path[] listedPaths = FileUtil.stat2Paths(status); 这里要注意FileUtil中的stat2Paths()方法的使用,它将一个FileStatus对象数组转化为Path对象数组,
System.out.println(listedPaths.length);
for (Path p : listedPaths)
FileInputFormat.addInputPath(job, new Path(p.toString()));
数据流
read对象返回一个FSDataInputStream。FSDataInputStream类转而封装DFSInputStream对象,改对象管理者datenode和NameNode的I/O。存储着文件起始块的datanode地址的DFSInputStream随即连接距离最近的datanode。通过对数据流反复调用read()方法,可以将数据从datanode传输到客户端。
在读取数据时候,如果DFSInputStream在与datanode通信时遇到错误,它便会尝试从这个块最邻近的一个datanode上读取数据,它也会记录这个故障datanode,以保证不会反复的读取该节点上后续的块。DFSInputStream也会通过校验和确认从datanode发来的数据是否完整。它就会在DFSInputStream试图从其他快datanode读取一个块的副本之前通知namenode。
这样设计的一个重点是,namenode告知客户端每个块中最佳的datanode,并且客户端直接联系该datanode且检索数据。由于数据流分散在该集群中的所有datanode,所以这种设计能够使HDFS可扩展到大量的并发客户端
过程2是一个DFS对namenode的远程RPC调用,在文件命名空间中创建一个新文件,此时该文件中还没有相应的数据块。namenode执行各种不同的检查以确保这个文件不存在,并且客户端有创建该文件的权限。
FSDataOutputStream将它分成一个个的数据包,并写入内部队列,成为“数据队列”,DataStreamer处理数据队列,它的责任是根据datanode列表来要求namenode分配合适的新块来存储数据备份。这一组datanode构成一个管线。假设副本数为3,所以管线中有三个节点,DataStream将数据包流式的传给第一个datanode,该datanode存储数据包并将它发送到管线中的第二个datanode。同样地,第2个datanode存储该数据包并且发送给管线中的第三个datanode。DSFOutputStream中以维护着一个内部数据队列来等待datanode的收到确认回执,成为“确认队列”。当管道中所有的datanode都收到确认信息后,该数据包才会从确认队列删除。
副本的布局:hadoop的默认布局策略是,运行客户端的节点上放第一个副本(如果客户端运行在集群之外,就随机选择一个节点,不过系统会避免挑选那些存储太满或者太忙的节点),第二个复本放在与第一个不同且随机另外选择的机架节点上(离架),第三个复本与第二个复本放在相同机架上,切随机选择另一个节点。其他的复本就是随机存放,不过系统会尽量避免在相同的机架上放太多的复本。
通过distcp并行复制
distcp 命令使用
hadoop distcp hdfs://namenode1/foo hdfs://namenode2/bar
用于集群之间传输数据
复制的时候会跳过目标路径下已经存在的文件,但是可以通过-overwrite和-update选项中的任意一个(或者两个)来覆盖或者只更新修改过的文件
hadoop distcp -update/-overwrite
hdfs://namenode1/foo hdfs://namenode2/bar
distcp 是作为一个MapReduce作业来实现的,该复制作业是通过集群中并行运行的map来完成的,这里没有reducer
每个map至少256M数据的复制
-m 参数是指定map的数量
通过这个参数可以保持一定情况下的HDFS集群的均衡。
然而这样也总不能阻止集群的不平衡,也许想限制map的数量以便另外一些节点可用于其他作业,若是这样,可以使用“均衡器”这个工具。
Hadoop文档的存档
hadoop存档文件或har文件,是一个高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,还能允许对文件进行透明的访问。具体来说,存档文件可以作为MapReduce的输入
hadoop archive -archiveName files.har /my/files/my
file.har是要存档的文件的名称,存档通过archive
删除文件 hadoop fs - rmr /my/files.har
不足就是创建一个har文件就会就要在原始文件的基础上,创建一个新的文档,要消耗文件容量大小的磁盘空间。虽然存档文件中中源文件能被压缩,但是不支持压缩文件压缩。