要获取hdfs上的文件信息,有两种方法:
- 通过JDK的java.net.URL
通过java.net.URL对象来打开一个欲从中读取数据的流(stream),在使用中这种方法时,需要为URL对象指定URLStreamHandlerFactory(),这样URL才能识别出hdfs://开头的标识。
这个方法在每个JVM中只能调用一次,所以它通常会被放在一个static block中执行(如下所示),但如果你的某部分程序——例如一个你无法修改源代码的第三方组件——已经调用了这个方法,那你就不能通过URL来这样读取数据了(下一节我们会介绍另一种方法)。
代码如下:
package com.hdfs.FileSyetem;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
/**
* 利用JDK的 java.net.URL对象来打开一个欲从中读取数据的流(stream)
* @author hadoop
*
*/
public class JavaUrl2Hdfs {
static{
URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
}
public static void main(String[] args) {
String uri ="hdfs://hadoop01:9000/user/hive/warehouse/student/student.txt";
InputStream in = null;
try {
in = new URL(uri).openStream();
IOUtils.copyBytes(in, System.out, 4096, false);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
IOUtils.closeStream(in);
}
}
}
- 使用FileSystem读取数据
就像上节所说的,有时候我们无法通过设置URLStreamHandlerFactory方法的方式来通过URL读取数据,这时FIleSystem API就派上用场了。
Hadoop文件系统中的文件是用Hadoop的Path对象来表示的(而不是java中的java.io.File对象,因为它的语义太接近于本地文件系统了)。你可以把一个Path对象看做Hadoop文件系统中的某一个URL,如上例中的“hdfs://hadoop01:9000/user/hive/warehouse/student/student.txt”。
Filesystem是一个通用的文件系统API,所以使用它的第一步就是先抽取出它的一个实例出来——在这个例子中是HDFS。下面列出了几个Filesystem的用于抽取Filesystem实例的几个静态方法:
public static FileSystem get(Configuration conf) throws IOException
public static FileSystem get(URI uri, Configuration conf) throws IOException
public static FileSystem get(URI uri, Configuration conf, String user) throws IOException
一个Configuration对象封装了客户端或服务器端的配置信息,这些配置信息是通过从conf/core-size.xml之类的配置文件中读取出来的名值对来设置的。下面我们一一说明上面的三个方法:
1)第一个方法返回一个默认的文件系统(在conf/core-site.xml中通过fs.default.name来指定的,如果在conf/core-site.xml中没有设置则返回本地文件系统)。
2)第二个方法通过uri来指定要返回的文件系统(例如,如果uri是上个测试例子中的hdfs://localhost/user/tom/quangle.txt,也即以hdfs标识开头,那么就返回一个hdfs文件系统,如果uri中没有相应的标识则返回本地文件系统)。
3)第三个方法返回文件系统的机理同(2)是相同的,但它同时又限定了该文件系统的用户,这在安全方面是很重要的。
有时候你可能想要使用一个本地文件系统,你可以使用另一个很方便的方法:
public static LocalFileSystem getLocal(Configuration conf) throws IOException
得到一个文件系统的实例后,我们可以调用该实例的open()方法来打开某个给定文件的输入流(第一个方法使用一个默认的4KB的输入缓冲):
public FSDataInputStream open(Path f) throws IOException
public abstract FSDataInputStream open(Path f, int bufferSize) throws IOExceptio
把上面介绍的组合起来我们就得到了下面的代码:
package com.hdfs.FileSyetem;
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 {
/**
* 获取hdfs上的所有文件,以及文件夹
* @param args
* @throws IOException
* @throws InterruptedException
*/
public static void main(String[] args) throws IOException, InterruptedException {
String uri ="hdfs://hadoop01:9000/user/hive/warehouse/student/student.txt";
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);
}
}
}