Hadoop学习(2)Eclipse配置Hadoop开发环境+HDFS Java API测试+Bug解决记录

目录

参考:

1. 添加插件

2. 在Windows上安装Hadoop2.9.1

(1)在本地安装Hadoop

(2)配置Hadoop的环境变量

(3)修改hadoop-env.cmd文件中的JAVA_HOME

(4)添加Windows支持文件(winutils.exe,hadoop.dll)

(5)重启Eclipse(File->Restart)

3. Eclipse中的配置

4. 创建HDFS测试项目(Maven工程)

测试代码1:

(1)错误1:

(2)错误2:

(3)错误3:

(4)错误4:

问题总结:

测试代码2:

测试代码3:

测试代码4:

测试代码5:

copyToLocalFile方法报错:


参考:

https://www.cnblogs.com/qingyunzong/p/8528134.html

1. 添加插件

下载在Windows Eclipse上需要的一些额外的文件:hadoop-eclipse=plugin-2.7.3.jar、winutils.exe,hadoop.dll,下载地址为链接:https://pan.baidu.com/s/1XpQ4qXGN4XzgwLNsraDKpQ 密码:obej,然后将hadoop-eclipse=plugin-2.7.3.jar包,并放入到eclipse的plugins文件夹中。

2. 在Windows上安装Hadoop2.9.1

(1)在本地安装Hadoop

我的Hadoop集群版本也是2.9.1(本地与集群版本最好一致)。将之前搭建集群所用的hadoop-2.9.1.tar.gz解压到Windows某目录下,我的是:E:\softwares\hadoop\hadoop-2.9.1,如下:

(2)配置Hadoop的环境变量

HADOOP_HOME=E:\softwares\hadoop\hadoop-2.9.1

Path=E:\softwares\hadoop\hadoop-2.9.1\bin

(3)修改hadoop-env.cmd文件中的JAVA_HOME

hadoop-env.cmd文件在hadoop的安装目录E:\softwares\hadoop\hadoop-2.9.1\下的etc\hadoop\下,我的JAVA_HOME是:C:\Program Files\Java\jdk1.8.0_144。修改完hadoop-env.cmd文件中的JAVA_HOME测试,查看hadoop版本:

经查证,是在hadoop-env.cmd中写JAVA_HOME的路径中出现了问题,本来路径确实是C:\Program Files\Java\jdk1.8.0_144,但路径名称“Program Files”中有空格导致了出错,解决方法如下:

解决参考:

发现原来是路径上包含了一个空格,所以有以下2个解决办法:

1.用路径替代符 C:\Progra~1\Java\jdk1.8.0_144,Progra~1是 C:\Program Files目录的dos文件名模式下的缩写,长于8个字符的文件名和文件夹名,都被简化成前面6个有效字符,后面~1,有重名的就 ~2,~3。

2.用引号括起来 "C:\Program Files"\Java\jdk1.8.0_144

参考:https://blog.csdn.net/wen3011/article/details/54907731

根据上面的思路,将hadoop-env.cmd中的JAVA_HOME的路径设置成C:\Progra~1\Java\jdk1.8.0_144,如下:

然后运行hadoop version,成功显示版本信息:

(4)添加Windows支持文件(winutils.exe,hadoop.dll)

  • 1)winutils.exe 放在windows平台中你安装的hadoop的bin目录下

  • 2)  hadoop.dll 放在windows操作系统的 c:/windows/system32目录下

(5)重启Eclipse(File->Restart)

出现问题:点击如下田字格图标,并没有出现“小象”Map/Reduce的图标

点击Windows-->Preferences查看,也未出现Hadoop Map/Reduce。

解决参考:

这种现象一般由于安装在eclipse\plugins下的插件没有导入的问题。解决方法:把 eclipse\configuration\org.eclipse.update 删除掉。出现这种情况的原因是在你安装新的插件以前你启动过 eclipse ,在 org.eclipse.update 文件夹下记录了插件的历史更新情况,它只记忆了以前的插件更新情况,而你新安装的插件它并不记录。

参考:https://blog.csdn.net/qq_30879741/article/details/72934480

根据上面的思路,我将E:\Eclipse\java-photon\eclipse\configuration\org.eclipse.update\下原先的文件platform.xml删掉,然后重启Eclipse(File->Restart),这次小象的图标就出现了,而且在Window-->Preferences下也出现了Hadoop Map/Reduce。

删掉,然后重启Eclipse,点击右上角“田字格"图标,出现“小象”Map/Reduce的图标,如下(网上有很多说eclipse版本的问题,很多删除eclipse重装的,我觉得此方法太暴力,可能不是版本问题,就是这个org.eclipse.update的问题,它没有及时更新eclipse的变化。我的eclipse版本:Photon Release (4.8.0)):

点击Window-->Preferences查看,出现Hadoop Map/Reduce:

3. Eclipse中的配置

(1)点击Window->Preferences->Hadoop Map/Reduce,设置Hadoop的安装目录:E:\softwares\hadoop\hadoop-2.9.1

(2)打开Hadoop开发视图:Window->Perspective->Open Perspective->Other...,在出现的如下对话框中选择小象Map/Reduce

然后右上角会出现小象图标,以表示是Hadoop开发的视图(Perspective)(以后可直接点击这里的小象图标切换到Hadoop开发视图中):

(3)打开Map/Reduce Locations,Window->Show view->Other...,出现如下弹窗,然后选择MapReduce Tools下的Map/Reduce Locations:

选择后eclipse左侧的Project Explorer会出现左侧的DFS Locations,同时也会出现Map/Reduce Locations的view,如下:

新建Hadoop连接:在上图说显示的Map/Reduce Locations的view中右键,选择New Hadoop Location...,出现如下弹框,然后填写相关配置信息:

配置成功后左侧的DFS Locations显示如下:

而这正与我的Hadoop HDFS的目录结构一致:

4. 创建HDFS测试项目(Maven工程)

测试代码1:

package demo.MavenTest;
import java.net.URI;
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 HdfsClientTest {

	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(new URI("hdfs://10.10.129.200:9000"), conf, "hadoop");

        //测试查看HDFS根目录
		FileStatus[] listStatus = fs.listStatus(new Path("/"));
		for (FileStatus fileStatus : listStatus) {
			System.out.println(fileStatus);
		}//end for
  fs.close();
	}//end main

}//end class

对应的pom依赖如下:

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.9.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
    <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>2.9.1</version>
</dependency>

运行程序:(Run as->Run on hadoop)

(1)错误1:

Exception in thread "main" java.lang.NoClassDefFoundError: com/ctc/wstx/io/InputBootstrapper

解决:添加pom依赖(参考:https://zhuanlan.zhihu.com/p/38630695):

<!-- https://mvnrepository.com/artifact/com.fasterxml.woodstox/woodstox-core -->
<dependency>
    <groupId>com.fasterxml.woodstox</groupId>
    <artifactId>woodstox-core</artifactId>
    <version>5.0.3</version>
</dependency>

保存后重新运行,出现错误2:

(2)错误2:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/collections/map/UnmodifiableMap

解决:添加pom依赖:

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.2</version>
</dependency>

保存后重新运行,出现错误3:

(3)错误3:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/configuration/Configuration

解决:添加pom依赖:

<!-- https://mvnrepository.com/artifact/commons-configuration/commons-configuration -->
<dependency>
    <groupId>commons-configuration</groupId>
    <artifactId>commons-configuration</artifactId>
    <version>1.6</version>
</dependency>

保存后重新运行,出现错误4:

(4)错误4:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/util/PlatforName

解决:添加pom依赖(参考:https://blog.csdn.net/Xgx120413/article/details/51889743):

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-auth -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-auth</artifactId>
    <version>2.9.1</version>
</dependency>

保存后重新运行,程序执行成功:

问题总结:

按说添加了hadoop-common和hadoop-hdfs后,其相应的一些依赖都会下载到本地mvn库,可能在下载时有漏掉一些依赖,每个人这时的错误提示可能有所不一样,但只需要根据错误提示,在pom文件中补上程序运行所需要的依赖即可。我所加入的各个依赖的版本号。是依据于我搭建的Hadoop集群以及Windows本地Hadoop版本来的,查看这些依赖的jar包及版本号,可以在E:\softwares\hadoop\hadoop-2.9.1\share\hadoop\文件夹下的common文件夹和hdfs文件夹查看,例如hdfs文件夹:

这里hdfs文件夹下的jar包是hdfs核心包,在lib文件夹下是其依赖jar包,这些都会需要。在这里可以也查看到相应jar包的版本。

测试代码2:

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://10.10.129.200:9000"), conf, "hadoop");

//上传本地文件到HDFS
fs.copyFromLocalFile(new Path("C:/Users/a/Desktop/hadoopTest/hello.txt"), new Path("/test/input/javaApiTest.txt"));

fs.close();

执行成功,在左侧的DFS Locations里可以看到/test/input/下多了一个文件javaApiTest.txt,其中r3表示有3个副本。

测试代码3:

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://10.10.129.200:9000"), conf, "hadoop");

//上传(流式处理,更底层)
InputStream in = new FileInputStream(new File("C:/Users/a/Desktop/hadoopTest/hello.txt"));
FSDataOutputStream out = fs.create(new Path("/test/input/javaApiTest2.txt"));
IOUtils.copyBytes(in, out, 4096, true);

fs.close();

执行成功,在左侧的DFS Locations里可以看到/test/input/下多了一个文件javaApiTest2.txt,其中r3表示有3个副本。

测试代码4:

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://10.10.129.200:9000"), conf, "hadoop");

//下载(流式处理,更底层)
FSDataInputStream in2 = fs.open(new Path("/test/input/words.txt"));
OutputStream out2 = new FileOutputStream(new File("C:/Users/a/Desktop/hadoopTest/words2.txt"));
IOUtils.copyBytes(in2, out2, 4096, true);

fs.close();

执行成功,可看到在C:\Users\a\Desktop\hadoopTest\文件夹下,已经下载下来文件words.txt:

测试代码5:

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://10.10.129.200:9000"), conf, "hadoop");

//从HDFS上下载文件到本地
fs.copyToLocalFile(new Path("/test/input/words.txt"), new Path("C:/Users/a/Desktop/hadoopTest/words.txt"));

fs.close();

copyToLocalFile方法报错:

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.
Exception in thread "main" java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.createFileWithMode0(Ljava/lang/String;JJJI)Ljava/io/FileDescriptor;
	at org.apache.hadoop.io.nativeio.NativeIO$Windows.createFileWithMode0(Native Method)
	at org.apache.hadoop.io.nativeio.NativeIO$Windows.createFileOutputStreamWithMode(NativeIO.java:556)
	at org.apache.hadoop.fs.RawLocalFileSystem$LocalFSFileOutputStream.<init>(RawLocalFileSystem.java:229)
	at org.apache.hadoop.fs.RawLocalFileSystem$LocalFSFileOutputStream.<init>(RawLocalFileSystem.java:219)
	at org.apache.hadoop.fs.RawLocalFileSystem.createOutputStreamWithMode(RawLocalFileSystem.java:314)
	at org.apache.hadoop.fs.RawLocalFileSystem.create(RawLocalFileSystem.java:302)
	at org.apache.hadoop.fs.RawLocalFileSystem.create(RawLocalFileSystem.java:334)
	at org.apache.hadoop.fs.ChecksumFileSystem$ChecksumFSOutputSummer.<init>(ChecksumFileSystem.java:399)
	at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:462)
	at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:441)
	at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:1067)
	at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:1048)
	at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:937)
	at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:391)
	at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:364)
	at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:314)
	at org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:2375)
	at org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:2344)
	at org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:2320)
	at demo.MavenTest.HdfsClientTest.main(HdfsClientTest.java:52)

查看copyToLocalFile的源码:

public void copyToLocalFile(Path src, Path dst) throws IOException {
    copyToLocalFile(false, src, dst);
}

继续跟踪:

public void copyToLocalFile(boolean delSrc, Path src, Path dst)throws IOException {
    copyToLocalFile(delSrc, src, dst, false);
}

继续跟踪:


  /**
   * The src file is under this filesystem, and the dst is on the local disk.
   * Copy it from the remote filesystem to the local dst name.
   * delSrc indicates if the src will be removed
   * or not. useRawLocalFileSystem indicates whether to use RawLocalFileSystem
   * as the local file system or not. RawLocalFileSystem is non checksumming,
   * So, It will not create any crc files at local.
   *
   * @param delSrc
   *          whether to delete the src
   * @param src
   *          path
   * @param dst
   *          path
   * @param useRawLocalFileSystem
   *          whether to use RawLocalFileSystem as local file system or not.
   *
   * @throws IOException for any IO error
   */
  public void copyToLocalFile(boolean delSrc, Path src, Path dst,
      boolean useRawLocalFileSystem) throws IOException {
    Configuration conf = getConf();
    FileSystem local = null;
    if (useRawLocalFileSystem) {
      local = getLocal(conf).getRawFileSystem();
    } else {
      local = getLocal(conf);
    }
    FileUtil.copy(this, src, local, dst, delSrc, conf);
  }

参数1->delSrc表示:是否要深处源文件;

参数2->src表示:要copy的源文件路径;

参数3->dst表示:copy的目标文件路径;

参数4->useRawLocalFileSystem表示:注释上说useRawLocalFileSystem指示是否使用RawLocalFileSystem作为本地文件系统。

关于参数useRawLocalFileSystem的解释网上找了主要有2种:

hadoop是一个综合文件系统,并不等价于hdfs文件系统。hadoop集成了众多的文件系统, hdfs仅仅是hadoop旗舰级文件系统。Hadoop的这个特点充分体现了hadoop的优良的可扩展性。在hadoop里,hadoop定义了一个抽象的文件系统的概念,类:org.apache.hadoop.fs.FileSystm,这个抽象类用来定义hadoop中的一个文件系统接口,只要某个文件系统实现了这个接口,就可以作为hadoop支持的文件系统。

Hadoop LocalFileSystem是客户端校验的类。在使用LocalFileSystem写文件时,会透明的创建一个.filename.crc的文件。 校验文件大小的字节数由io.bytes.per.checksum属性设置,默认是512bytes,即每512字节就生成一个CRC-32校验和。.filename.crc文件会存 io.bytes.per.checksum的信息。在读取的时候,会根据此文件进行校验。事实上LocalFileSystem是通过继承ChecksumFileSystem实现校验的工作。

文件

系统

URI

方案  

Java实现

(org.apache.hadoop)

定义

Local

file

fs.LocalFileSystem

支持有客户端校验和本地文件系统。

带有校验和的本地系统文件在fs.RawLocalFileSystem中实现。

从上面内容可知,当设置useRawLocalFileSystem为true时就是指使用Hadoop LocalFileSystem,即开启校验。所以参数useRawLocalFileSystem就是表示是否开启文件校验。

解决:将代码 fs.copyToLocalFile(new Path("/test/input/words.txt"), new Path("C:/Users/a/Desktop/hadoopTest/words.txt"));改为 fs.copyToLocalFile(false, new Path("/test/input/words.txt"), new Path("C:/Users/a/Desktop/hadoopTest/words.txt"), true);后程序即可执行成功,在C:\Users\a\Desktop\hadoopTest\文件夹下多了文件words.txt。

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://10.10.129.200:9000"), conf, "hadoop");

//从HDFS上下载文件到本地
//fs.copyToLocalFile(new Path("/test/input/words.txt"), new Path("C:/Users/a/Desktop/hadoopTest/words.txt"));
fs.copyToLocalFile(false, new Path("/test/input/words.txt"), new Path("C:/Users/a/Desktop/hadoopTest/words.txt"), true);

fs.close();

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章