通过HDFS FileSystem API 对 HDFS 进行操作

windows下安装eclipse-hadoop插件

  1. 将hadoop-eclipse-plugin-2.6.0.jar复制到eclipse安装目录下的plugins文件夹中。
  2. 将hadoop.dll和winutils.exe复制到Windows的hadoop安装目录的bin文件夹下
  3. Windows解压hadoop2.7.3
  4. 配置环境变量:HADOOP_HOME = D:/hadoop2.7.3;
    【配置PATH属性:%HADOOP_HOME%\bin;%HADOOP_HOME%\sbin】
  5. eclipse–>[windows]–>[首选项]–>[hadoop MapReduce]

【设置hadoop的安装目录】

  1. 打开【Mapreduce Locations】视图窗口 --> 右键 --> 【new Hadoop location】

Location name:mumu #随意名字
Map/Redce(v2) Master DFS Master host:master host:master
port:9001 post:9000
User name:hadoop #集群用户名

  1. 打开Map/Reduce编程视图【集群开启就会自动连接】
    右键 --> Reconnect

通过Java URL方式访问HDFS【成功】

【FromURLJHadoop.java】
package com.hyxy.hadoop.hdfs;

import java.io.InputStream;
import java.net.URL;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;

public class FromURLJHadoop {
   static{
	   URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
   }

   public static void main(String[] args) {
	  InputStream io = null;
	  try {
		io = new URL("hdfs://master:9000/tree.txt").openStream();
		IOUtils.copyBytes(io, System.out, 4096, false);
	  } catch (Exception e) {
		e.printStackTrace();
	  }finally {
		IOUtils.closeStream(io);
	  }
   }
}

测试Java API 的 URL 对 HDFS 进行写操作【失败】

package com.hyxy.hadoop.hdfs;

import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;

public class ToURLHadoop {
	static {
		URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
	}
	
	public static void main(String[] args) throws Exception {
		OutputStream out = null;
		try {
			URLConnection conn = new URL("hdfs://master:9000/mumu/geek/tree.txt").openConnection();
			out = conn.getOutputStream();
			out.write("hello world".getBytes());
			out.close();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}

log4j:WARN No appenders could be found for logger (org.apache.hadoop.metrics2.lib.MutableMetricsFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
java.net.UnknownServiceException: protocol doesn’t support output
at java.net.URLConnection.getOutputStream(URLConnection.java:843)
at com.hyxy.hadoop.hdfs.ToURLHadoop.main(ToURLHadoop.java:19)

主要代码分析

【configuration只加载core-site.xml】

  • 【org.apache.hadoop.conf.Configuration】类说明或作用:
  1. [Resource]:资源定义及加载

资源默认按顺序加载:core-site.xml --> core-site.xml --> 代码段

资源描述以name/value键值对定义。

  1. [Final Parameters]:不变参数

配置参数可以声明为final。一旦资源声明了一个值是final,以后加载的资源就不能更改该值

  1. [Variable Expansion]:参数表达式

值字符串首先处理变量展开

  • Configuration用法:如果访问hdfs,在Java API 中需调用以下几种方式,来获取Resources
  1. 通过conf.set(“fs.defaultFS”, “hdfs://master:9000”);
  2. 通过conf.addResource(“core”); #将core-site.xml复制到classpath下,命名为core
  3. 将core-site.xml文件拷贝到classpath下,默认加载core-default.xml,然后加载core-site.xml中重写项
  • 【写数据到HDFS中的文件中】【开启HDFS文件系统可以用FileSystem也可以用其实现类DistributedFileSystem】
package com.hyxy.hadoop.hdfs;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

public class HDFSDemo {
	
	public static void main(String[] args) {
		readDataFromHDFS();
	}
	
	public static void readDataFromHDFS() {
		Configuration conf = new Configuration();
		System.out.println(conf.get("fs.defaultFS"));
		//方式一、常用这种,这是具体的设置,集群使用默认的配置文件,但在具体的业务下,使用set是走代码,覆盖配置,但不会更改配置文件内容,就不会更改整个集群的配置
		//conf.set("fs.defaultFS", "hdfs://master:9000");
		//方式二、
		//conf.addResource("core");
		//方式三、将core-site.xml拷到src下,默认加载,常用这种
		
		System.out.println(conf.get("fs.defaultFS"));
		try {
			FileSystem fs = FileSystem.get(conf);
			Path file = new Path("hdfs://master:9000/Hello.java");
			FSDataInputStream fsinput = fs.open(file);
			IOUtils.copyBytes(fsinput, System.out, 4096, false);
			fsinput.close();
			fs.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
  • 默认情况下,先加载core-default.xml,然后加载core-site.xml
    在【org.apache.hadoop.conf.Configuration】第649行,静态代码块中执行。
  • FileSystem抽象类一般实现类为两类:【DistributedFileSystem】和【LocalFileSystem】
  • 调整相关参数时,个别全局变量需在集群端修改,重启生效。
  • 【创建目录】
  1. 修改根目录的权限

$>hadoop fs -chmod -R +w /

package com.hyxy.hadoop.hdfs;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DistributedFileSystem;

public class HDFSDemo2 {
	
	public static void main(String[] args) {
		mkdirByAPI();
	}
	
	public static void mkdirByAPI() {
		Configuration conf = new Configuration();
		try {
			DistributedFileSystem dfs = (DistributedFileSystem) FileSystem.get(conf);
			//代码方式创建文件夹
			dfs.mkdirs(new Path("/dir"));
			dfs.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
  • 【获取文件或目录详情】
package com.hyxy.hadoop.hdfs;

import java.io.IOException;

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 org.apache.hadoop.hdfs.DistributedFileSystem;

public class HDFSDemo3 {
	
	public static void main(String[] args) {
		getFileStatus();
	}
	
	public static void getFileStatus() {
		Configuration conf = new Configuration();
		try {
			DistributedFileSystem dfs = (DistributedFileSystem) FileSystem.get(conf);
			//获取文件或目录的详情
			FileStatus fst = dfs.getFileStatus(new Path("/Hello.java"));
			System.out.println("getAccessTime:" + fst.getAccessTime());
			System.out.println("getBlockSize:" + fst.getBlockSize());
			System.out.println("getGroup:" + fst.getGroup());
			System.out.println("getLen:" + fst.getLen());
			System.out.println("getReplication:" + fst.getReplication());
			System.out.println("getPermission:" + fst.getPermission());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
  • 【获取文件路径或目录子文件及子目录列表】
package com.hyxy.hadoop.hdfs;

import java.io.IOException;

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 org.apache.hadoop.hdfs.DistributedFileSystem;

public class HDFSDemo4 {
	
	public static void main(String[] args) {
		getFileStatusArray();
	}
	
	public static void getFileStatusArray() {
		Configuration conf = new Configuration();
		try {
			DistributedFileSystem dfs = (DistributedFileSystem) FileSystem.get(conf);
			//获取文件路径或目录子文件及子目录列表
			FileStatus[] fst_arr = dfs.listStatus(new Path("/"));
			Path[] path_arr = FileUtil.stat2Paths(fst_arr);
			for(Path path : path_arr) {
				System.out.println(path);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
  • 【通过API进行写操作,覆盖操作】
  1. 可以指定副本数,块大小,但是块大小若小于默认最小值,则必须在集群中修改默认参数,并重启集群
  2. 同时还要设置校验和的大小,不过校验和可以在客户端修改
package com.hyxy.hadoop.hdfs;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DistributedFileSystem;

public class HDFSDemo5 {
	//通过API进行写操作
	public static void main(String[] args) {
		writeByAPI();
	}
	
	public static void writeByAPI() {
		Configuration conf = new Configuration();
		//conf.set("dfs.namenode.fs-limits.min-block-size", "1");【客户端设置是无效的】
		conf.set("dfs.bytes-per-checksum", "1");
		try {
			DistributedFileSystem dfs = (DistributedFileSystem) FileSystem.get(conf);
			Path file = new Path("hdfs://master:9000/test.java");
			//FSDataOutputStream fsos = dfs.create(file);
			FSDataOutputStream fsos = dfs.create(file, true, 4096, (short)2, 3);
			fsos.writeBytes("Hello China!");
			System.out.println("ok");
			fsos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
  • 【通过API进行写操作,追加操作】
  1. 必须打开yarn,否则报错
package com.hyxy.hadoop.hdfs;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DistributedFileSystem;

public class HDFSDemo6 {
	//通过API进行追加写操作
	public static void main(String[] args) {
		writeByAPI();
	}
	
	public static void writeByAPI() {
		Configuration conf = new Configuration();
		conf.set("dfs.bytes-per-checksum", "1");【必须写,因为test.java创建时,块大小设置为3】
		【如果是其他文件,则不能修改校验和】
		try {
			DistributedFileSystem dfs = (DistributedFileSystem) FileSystem.get(conf);
			Path file = new Path("hdfs://master:9000/test.java");
			FSDataOutputStream fsos = dfs.append(file);
			fsos.writeBytes("Hello China!");
			System.out.println("ok");
			fsos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}