1 环境准备
将在Windows环境中编译过的hadoop jar包解压缩到非中文路径;
设置环境变量:
打开IDEA,创建一个Maven工程;
在pom.xml文件中添加如下依赖,点击右上角的Load Maven Changes开始下载依赖;
1 <dependencies> 2 <dependency> 3 <groupId>junit</groupId> 4 <artifactId>junit</artifactId> 5 <version>RELEASE</version> 6 </dependency> 7 <dependency> 8 <groupId>org.apache.logging.log4j</groupId> 9 <artifactId>log4j-core</artifactId> 10 <version>2.8.2</version> 11 </dependency> 12 <dependency> 13 <groupId>org.apache.hadoop</groupId> 14 <artifactId>hadoop-common</artifactId> 15 <version>2.7.2</version> 16 </dependency> 17 <dependency> 18 <groupId>org.apache.hadoop</groupId> 19 <artifactId>hadoop-client</artifactId> 20 <version>2.7.2</version> 21 </dependency> 22 <dependency> 23 <groupId>org.apache.hadoop</groupId> 24 <artifactId>hadoop-hdfs</artifactId> 25 <version>2.7.2</version> 26 </dependency> 27 <dependency> 28 <groupId>jdk.tools</groupId> 29 <artifactId>jdk.tools</artifactId> 30 <version>1.8</version> 31 <scope>system</scope> 32 <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> 33 </dependency> 34 </dependencies>
在项目的resources目录下,新建一个file文件,命名为"log4j.properties",并添加如下内容;
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
2 使用FileSystem对象的方法操作hdfs
@Test public void testHdfsJavaAPI() throws URISyntaxException, IOException, InterruptedException { // 1 获取FileSystem对象 Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.10.102:9000"), conf, "wm"); // 2 创建文件目录 fs.mkdirs(new Path("/hdfsPath")); // 3 上传文件 fs.copyFromLocalFile(new Path("D:/localFile.txt"), new Path("/hdfsPath/hdfsFile.txt")); // 4 下载文件 fs.copyToLocalFile(new Path("/hdfsPath/hdfsFile.txt"), new Path("D:/localFile2.txt")); // 5 删除文件 fs.delete(new Path("/hdfsPath"), true); // 6 关闭资源 fs.close(); }
客户端与hdfs文件系统的连接,首先需要一个FileSystem对象,它起到“桥梁”的作用。FileSystem类有一个静态的get()方法,用于返回FileSystem对象。get()方法共有3个参数,分别是:hdfs中NameNode地址、Configuration对象、访问的用户名。其中,FileSystem在org.apache.hadoop.fs包下,Configuration在org.apache.hadoop.conf包下,URI在Java.net包下。new URI()会抛出异常URISyntaxException,FileSystem.get()会抛出异常IOException、InterruptedException。
// 1 获取FileSystem对象 Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.10.102:9000"), conf, "wm");
FileSystem对象的mkdirs(hdfsFilePath)方法用于创建hdfs文件目录。其中,Path类在org.apache.hadoop.fs包下。
// 2 创建文件目录 fs.mkdirs(new Path("/hdfsPath"));
FileSystem对象的copyFromLocalFile(localFilePath, hdfsFilePath)方法用于从本地上传文件至hdfs系统,copyToLocalFile(hdfsFilePath, localFilePath)方法用于下载文件。
// 3 上传文件 fs.copyFromLocalFile(new Path("D:/localFile.txt"), new Path("/hdfsFile.txt")); // 4 下载文件 fs.copyToLocalFile(new Path("/hdfsFile.txt"), new Path("D:/localFile2.txt"));
FileSystem对象的delete(hdfsPath, boolean)方法用于删除hdfs文件目录或文件,第二个参数为true时,表示递归删除。
// 5 删除文件 fs.delete(new Path("/hdfsPath"), true);
最后,关闭FileSystem对象资源。
// 6 关闭资源 fs.close();
3 使用流对象操作hdfs
// 上传文件至hdfs @Test public void testPutFileToHdfs() throws URISyntaxException, IOException, InterruptedException { // 1 获取FileSystem对象 Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.10.102:9000"), conf, "wm"); // 2 获取输入流 FileInputStream fis = new FileInputStream("D:/localFile.txt"); // 3 获取输出流 FSDataOutputStream fos = fs.create(new Path("/hdfsFile.txt")); // 4 数据传输 IOUtils.copyBytes(fis, fos, conf); // 5 关闭资源 IOUtils.closeStream(fos); IOUtils.closeStream(fis); fs.close(); }
首先,获取FileSystem对象。
// 1 获取FileSystem对象 Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.10.102:9000"), conf, "wm");
之后,获取输入流与输出流对象。当从本地上传文件至hdfs时,本地文件是输入流,hdfs文件是输出流;当从hdfs下载文件至本地时,hdfs文件是输入流,本地文件是输出流。下面以上传文件为例。输入流FileInputStream对象通过实例化FileInputStream类得到,构造函数参数为本地文件路径。输出流FSDataOutputStream对象通过FileSystem对象的create(hdfsPath)方法得到。
// 2 获取输入流 FileInputStream fis = new FileInputStream("D:/localFile.txt"); // 3 获取输出流 FSDataOutputStream fos = fs.create(new Path("/hdfsFile.txt"));
输入流和输出流都获取完毕后,使用IOUtils类的静态方法copyBytes(InputStream,OutputStream,Configuration)进行流之间的数据传输。
// 4 数据传输 IOUtils.copyBytes(fis, fos, conf);
最后,关闭资源。
// 5 关闭资源 IOUtils.closeStream(fos); IOUtils.closeStream(fis); fs.close();
从hdfs下载文件至本地类似,只是输入流和输出流的获取有些变化,代码如下。
// 从hdfs下载文件至本地 @Test public void testGetFileFromHdfs() throws URISyntaxException, IOException, InterruptedException { // 1 获取FileSystem对象 Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.10.102:9000"), conf, "wm"); // 2 获取输入流 FSDataInputStream fis = fs.open(new Path("/hdfsFile.txt")); // 3 获取输出流 FileOutputStream fos = new FileOutputStream("D:/localFile.txt"); // 4 数据传输 IOUtils.copyBytes(fis, fos, conf); // 5 关闭资源 IOUtils.closeStream(fos); IOUtils.closeStream(fis); fs.close(); }
如果只是想在客户端查看hdfs文件的内容而不下载至本地,也是可以的,此时输出流可以换成System.out对象。代码如下。
// 查看hdfs文件内容 @Test public void testCatFile() throws URISyntaxException, IOException, InterruptedException { // 1 获取FileSystem对象 Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.10.102:9000"), conf, "wm"); // 2 获取输入流 FSDataInputStream fis = fs.open(new Path("/hdfsFile.txt")); // 3 获取输出流 OutputStream os = System.out; // 4 数据传输 IOUtils.copyBytes(fis, os, conf); // 5 关闭资源 IOUtils.closeStream(fis); IOUtils.closeStream(os); fs.close(); }
参考:
《Hadoop权威指南 大数据的存储与分析-第4版》