API开发的运行环境配置
第一步:解压Hadoop-2.7.3.tar.gz
第二步:在windows->preferences->Hadoop map/reduce配置hadoop的安装路径(根目录)
第三步: 配置环境变量
HADOOP_HOME:E:\1705Linux\Hadoop\hadoop-2.7.3(new)\hadoop-2.7.3
PATH:%HADOOP_HOME%\bin;%HADOOP_HOME%\sbin
注意:
在写代码时,会出现Log4J警告:
解决办法:将hadoop-2.7.3\etc\hadoop\下的log4j.properties文件复制到src下
如果出现异常:Could not locate executable %HADOOP_HOME%\bin\winutils.exe in the Hadoop binaries.
解决办法:把winutils和hadoop.dll 复制到%HADOOP_HOME%\bin\里面
从Hadoop URL读取数据
要从Hadoop文件系统读取文件,最简单的方法就是使用java.net.URL对象打开数据流,从中读取是数据。
第一步:新建Java工程,并添加所需要的jar包,再创建测试类
第二步:打开测试类,填写代码
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;
import org.junit.Test;
public class TestURL {
//通过FsUrlStreamHandlerFactory实例调用java.net.URL对象的setURLStreamHandlerFactory()方法
//注意: 每个java虚拟机只能调用一次这个方法,因此通常在静态方法中调用。
static {
URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
}
@Test
public void testURL() throws IOException{
URL url = new URL("hdfs://192.168.172.150:9000/a");
//使用java.net.URL对象打开数据流,从中读取数据
InputStream is = url.openStream();
//调用IOUtils的copyBytes()方法,在输入流与输出流之间复制数据
IOUtils.copyBytes(is, System.out, 10,false);
IOUtils.closeStream(is);
}
}
通过FileSystem API读取数据
import java.io.IOException;
import java.io.InputStream;
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.junit.Test;
public class TestAPI1 {
@Test
public void testFileSystem() throws IOException{
/*
* 创建Configuration对象,加载配置文件信息:包含hadoop-common-2.7.3.jar里的core-default
* 和src下的core-site.xml
*/
Configuration conf = new Configuration();
/*
* 通过FileSystem提供的静态方法get(Configuration conf)获取FileSystem的具体实例,
*/
FileSystem fs = FileSystem.get(conf);
/*
* 通过Hadoop Path对象来代表文件,可以将路径视为Hadoop 文件系统的URI
*/
Path path = new Path("hdfs://192.168.172.150:9000/a");
/*
* 通过FileSystem的实例,调用open方法。
* fs.open(Path path)方法 来进行一些权限,路径等校验,
* 如果校验通过,就返回一个输入流
*/
InputStream input = fs.open(path);
/*
* 调用IOUtils的copyBytes()方法,
* 在输入流与输出流之间复制数据
*/
IOUtils.copyBytes(input, System.out,10,false);
IOUtils.closeStream(input);
}
}
通过FSDataInputStream对象读取数据
实际上,FileSystem对象中的open()方法返回的是FSDataInputStream对象,而不是标准的java.io类对象。
这个类是继承了java.io.DataInputStream的一个特殊类,并支持随机访问,由此可以从流的任意位置读取数据。
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;
import org.junit.Test;
public class TestAPI2 {
@Test
public void TestFSDataInputStream() throws IOException{
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path path = new Path("hdfs://192.168.172.150:9000/c");
FSDataInputStream input = fs.open(path);
IOUtils.copyBytes(input, System.out, 10,false);
/*
* Seekable接口支持在文件中找到指定位置
* 并提供一个getPos()方法,
* 用来查询当前位置相对于文件起始位置偏移量
* 调用seek()方法来通过指针定位文件位置(不能超出文件长度)
*/
//回到文件起始位置
input.seek(0);
byte[] b = new byte[20];
//查询文件内容
input.read(b);
System.out.println(new String(b));
//查询当前位置
System.out.println("当前指针位置:"+input.getPos());
//将指针移动到文件的第3个位置,重新往后读取文件
input.seek(3);
System.out.println("移动指针之后的指针位置:"+input.getPos());
IOUtils.copyBytes(input, System.out, 10,false);
System.out.println("读取文件之后的指针位置"+input.getPos());
IOUtils.closeStream(input);
}
}
写入数据
FileSystem类有一系列新建文件的方法,最简单的方法就是给准备建的文件指定一个Path对象,然后返回一个写入数据的输出流。
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
/**
* 通过java api来连接HDFS进行写操作。
* 默认加载客户端上的默认配置信息,比如 blocksize =128M replication=3
*
* 相当于shell 接口的
* hadoop fs -put
*/
public class TestAPI3 {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path path = new Path("hdfs://192.168.172.150:9000/d5/d6/text1");
FSDataOutputStream output = fs.create(path);
output.write("hello kitty".getBytes());
IOUtils.closeStream(output);
//查询文件数据
FSDataInputStream input = fs.open(path);
IOUtils.copyBytes(input, System.out, 10,false);
IOUtils.closeStream(input);
}
}
创建目录
通常,你不需要显式创建一个目录,因为调用create()方法写入文件时会自动创建父目录
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
/*
* 相当于shell 接口的
* ]$ hadoop fs -mkdir -p /d3/d4
*/
public class TestAPI4 {
@Test
public void TestMkdir() throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path path = new Path("hdfs://192.168.172.150:9000/d3/d4");
boolean b = fs.mkdirs(path);
System.out.println("目录是否创建成功:"+b);
}
}
查询文件系统
任何文件系统的一个重要特征都是提供其目录结构,浏览和检索它所存文件和目录相关信息的功能。
FileStatus类封装了文件系统中文件和目录的元数据,包括文件长度、块大小、复本、修改时间、所有者以及权限信息。
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;
public class TestAPI5 {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path path = new Path("hdfs://192.168.172.150:9000/a");
/*
* FileSystem的getFileStatus()方法
* 用于获取文件或目录的FileStatus对象
* /
FileStatus status = fs.getFileStatus(path);
System.out.println("AccessTime:"+status.getAccessTime());
System.out.println("BlockSize:"+status.getBlockSize());
System.out.println("Group:"+status.getGroup());
System.out.println("Len:"+status.getLen());
System.out.println("ModificationTime:"+status.getModificationTime());
System.out.println("Owner:"+status.getOwner());
System.out.println("Replication:"+status.getReplication());
System.out.println("Path:"+status.getPath());
System.out.println("Permission:"+status.getPermission());
}
}