- HDFS是Hadoop主要应用的一个分布式文件系统。Hadoop中有一个综合性的文件系统抽象,它提供了文件系统实现的各类接口,HDFS是这个抽象文件系统的一个实例。
- Hadoop整合了众多文件系统,它首先提供了一个高层的文件系统抽象
org.apache.hadoop.fs.FileSystem
,这个抽象类展示了一个分布式文件系统,并有几个具体实现,如下表.
文件系统 | URI方案 | Java实现(org.apache.hadoop) | 描述 |
---|---|---|---|
Local | file | fs.LoacalFileSystem | 支持有客户端校验和的文件系统 |
HDFS | hdfs | hdfs.DistributedFileSystem | Hadoop分布式文件系统 |
HFTP | hftp | hdfs.HftpFileSystem | 支持通过HTTP方式以只读方式访问HDFS |
HSFTP | hsftp | hdfs.HsftpFileSystem | 支持通过HTTPS方式以只读方式访问HDFS |
HAR | har | fs.HarFileSystem | 构建在其他文档系统上进行归档文件的文件系统 |
KFS | kfs | fs.kfs.KosmosFileSystem | Cloudstore文件系统,类似HDFS用C++编写 |
FTP | ftp | fs.ftp.FtpFileSystem | 有FTP服务器支持的文件系统 |
S3(本地) | s3n | fs.s3native.NativeS3FileSystem | 基于Amazon S3的文件系统 |
S3(基于块) | s3 | fs.s3.NativeS3FileSystem | 基于Amazon S3的文件系统,以块格式存储,解决了S3的5GB限制 |
Hadoop提供了许多文件系统的接口,用户可使用URI方案选取适合的文件系统来实现交互。
通过文件系统命令接口进行Hadoop文件系统的操作,例如:想要列出本地文件系统的目录:
hadoop fs -ls file:///
1、HDFS常用Java API详解
Hadoop FileSystem类就饿Hadoop文件系统进行交互的API
1-1、使用Hadoop URL 读取数据
从Hadoop中读取数据,最简单的方式是说那个java.net.URL对象打开一个数据流,并从中读取数据,一般的调用格式如下:
package HDFS;
import org.apache.hadoop.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by Promacanthus on 2017/6/30.
*/
public class URLClass {
public static void main(String[] args) {
InputStream inputStream = null;
try {
inputStream = new URL("hdfs://NameNodeIP/path").openStream();
IOUtils.copyBytes(inputStream,System.out,4096,false);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeStream(inputStream);
}
}
}
1-2、使用FileSystem API 读取数据
文件在Hadooop系统中被视为一个Hadoop Path 对象,可以把一个路径视为Hadoop的文件系统URI。
FileSystem API是一个高层抽象的文件系统API,首先要找到这里的文件系统实例HDFS,取得FileSystem实例有2个静态工厂方法:
public static FileSystem get(Configuration conf) throws IOException //返回默认文件系统,如果没有设置,则为默认的本地文件系统
public static FileSystem get(URI uri,Configuration conf)throws IOException //使用指定的URI方案决定文件系统的权限,如果指定的URI中没有指定方案,则退回默认的文件系统
Configuration对象分装了一个客户端或服务器的配置,这是用路径读取的配置文件设置的(core-site.xml)
有了FileSystem实例后,可以通过open()方法得到一个文件的输入流:
public FSDataInputStream open(Path f) throws IOException //直接使用默认的4KB缓冲区
public abstract FSDataInputStream open(Path f, int buffrSize) throws IOException
使用FileSystem API 显示Hadoop文件系统中的文件:
package HDFS;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* Created by Promacanthus on 2017/7/1.
*/
public class FileSystemAPI {
public static void main(String[] args) throws IOException {
String uri = "hdfs://NameNodeIP/path";
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri),conf);
InputStream in = null;
try {
in = fs.open(new Path(uri));
IOUtils.copyBytes(in,System.out,4096,false);
} finally {
IOUtils.closeStream(in);
}
}
}
1-3、创建目录
FileSystem提供了创建目录的方法:
public boolean mkdirs(Path f) throws IOException
这个方法会按照客户端请求创建未存在的父目录
1-4、删除数据
FileSystem的delete()方法可以永久删除Hadoop中的文件或目录
public boolean delete(Path f,boolean recursive) throws IOException
如果传入的f为空文件或空目录,recursive会被忽略,当recursive的值为ture,非空的文件或目录才会被删除
1-5写数据
FileSystem创建文件,最简单的方法,给创建的文件制定一个路径对象,然后返回一个写输出流:
public FSDataOutputStream create(Path f)throws IOException
该方法有很多重载方法,如:设定是否强制覆盖原文件,设定文件副本数,设置写入文件缓冲区大小,文件块大小,设置文件许可
新建文件可以使用apped()在一个已有文件中追加内容:
public FSDataOutputStream append(Path f) throws IOException
将本地文件复制到Hadoop文件系统并显示进度:
package HDFS;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import java.io.*;
import java.net.URI;
/**
* Created by Promacanthus on 2017/7/1.
*/
public class FileCopyWithProgress {
public static void main(String[] args) throws IOException {
String localsrc = args[0];
String dst = args[1];
InputStream in = new BufferedInputStream(new FileInputStream(localsrc));
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(dst),conf);
OutputStream out = fs.create(new Path(dst), new Progressable() {
public void progress() {
System.out.print("*");
}
});
IOUtils.copyBytes(in,out,4096,true);
}
}
1-6、文件系统查询
Java API提供了文件系统的基本查询接口,通过这个接口,可以查询系统的元数据信息和文件目录结构,并可以进行更复杂的目录匹配操作
1- 文件元数据:FileStatus()
文件系统具备的重要功能是定位器目录结构及检索区存储的文件和目录信息。FileStatus类封装了文件系统中文件和目录的元数据,其中包括文件长度,块大小,副本,修改时间,所有者和许可信息
FileSystem的getFileStatus()方法提供了获取一个文件或目录的状态对象的方法:
package HDFS;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.io.OutputStream;
/**
* Created by Promacanthus on 2017/7/1.
*/
public class ShowFileStatusTest {
private MiniDFScluster cluster;
private FileSystem fs;
public void setUp() throws IOException {
Configuration conf = new Configuration();
if (System.getProperty("test.bulid.data") == null) {
System.setProperty("test.bulid.data", "/tmp");
}
cluster = new MiniDFScluster(conf, 1, true, null);
fs = cluster.getFileSystem();
OutputStream out = fs.create(new Path("/dir/file"));
out.write("content".getBytes("UTF-8"));
out.close();
}
public void tearDown() throws IOException {
if (fs != null) {
fs.close();
}
if (cluster != null) {
cluster.shutdown();
}
}
public void throwsFileNotFoundForNonExistentFile() throws IOException {
fs.getFileStatus(new Path("no-such-file"));
}
public void fileStatusForFile() throws IOException {
Path file = new Path("/dir/file");
FileStatus stat = fs.getFileStatus(file);
assert (stat.getPath().toUri().getPath() == "/dir/file");
assert (stat.isDirectory() == false);
assert (stat.getLen() == 7L);
assert (stat.getModificationTime() == lessThanOrEqualTo(System.currentTimeMillis()));
assert (stat.getReplication() == (short) 1);
assert (stat.getBlockSize() == 64 * 1024 * 1024L);
assert (stat.getOwner() == "tom");
assert (stat.getGroup() == "supergroup");
assert (stat.getPermission().toString() == "rw-r--r--");
}
private Object lessThanOrEqualTo(long l) {
}
public void fileStatusForDirectory() throws IOException {
Path dir = new Path("/dir");
FileStatus stat = fs.getFileStatus(dir);
assert (stat.getPath().toUri().getPath()=="/dir");
assert (stat.isDirectory()==true);
assert (stat.getLen()==0L);
assert (stat.getModificationTime()==lessThanOrEqualTo(System.currentTimeMillis()));
assert (stat.getReplication()==(short) 0);
assert (stat.getBlockSize()==0L);
assert (stat.getOwner()=="tom");
assert (stat.getGroup()=="supergroup");
assert (stat.getPermission().toString()=="rwxr-xr-x");
}
2- 列出目录文件信息:listStatus()
- 传入参数是一个文件时,它会简单地返回长度为1的FileStatus对象的一个数组
- 传入参数为一个目录时,它会返回0个或多个FileStatus对象,代表该目录所包含的文件和子目录
listStatus()方法有许多重载的方法,可以用PathFilter来限制匹配的文件和目录,他如果把路径数组作为参数来调用listStatus()方法,其结果与一次对多个目录进行查询、在将FileStatus对象数组手机到一个单一的数组的结果是相同的
显示Hadoop文件系统中的一个目录的文件信息:
package HDFS;
import org.apache.hadoop.conf.Configuration;
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 java.io.IOException;
import java.net.URI;
/**
* Created by Promacanthus on 2017/7/1.
*/
public class ListStatus {
public static void main(String[] args) throws IOException {
String uri = args[0];
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);
Path[] paths = new Path[args.length - 1];
for (int i = 0; i < paths.length; i++) {
paths[i]=new Path(args[i]);
}
FileStatus[] statuses = fs.listStatus(paths);
Path[] listedPaths = FileUtil.stat2Paths(statuses);
for(Path p : listedPaths){
System.out.println(p);
}
}
}
3- 通过通配符实现目录筛选
Hadoop为通配符提供2个方法,可以在FileSystem中找到:
public FileStatus[] globStatus(Path pathPattern) throws IOException
public FileStatus[] globStatus(Path pathPattern,PathFilter filter) throws IOException
globStatus()方法返回其路径匹配所提供的FileStatus对象数组,再按照路径进行排序,其中可选的PathFilter命令可以进一步限定匹配。
Hadoop支持的通配符及其作用
通配符 | 名称 | 功能 |
---|---|---|
* | 星号 | 匹配0个或多个字符 |
? | 问号 | 匹配一个字符 |
[ab] | 字符类别 | 匹配a,b中的一个字符 |
[^ab] | 非此字符类别 | 匹配不属于a,b中的一个字符 |
[a-b] | 字符范围 | 匹配[a,b]范围内的字符,a在字典顺序上小于b |
[^a-b] | 非此字符范围 | 匹配不属于[a,b]范围内的字符,a在字典顺序上小于b |
{a,b} | 或选择 | 匹配包含a或b中的语句 |
\c | 转义字符 | 匹配元字符c |
使用PathFilter排除匹配正则表达式的目录:
package HDFS;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathFilter;
/**
* Created by Promacanthus on 2017/7/1.
*/
public class RegexExcludePathFilter implements PathFilter{
private final String regex;
public RegexExcludePathFilter(String regex) {
this.regex = regex;
}
public boolean accept(Path path) {
return !path.toString().matches(regex);
}
}