Exception in thread "main" java.lang.IllegalArgumentException: Wrong FS: hdfs://master:9000/index.html, expected:
file:///
at org.apache.hadoop.fs.FileSystem.checkPath(FileSystem.java:390)
at org.apache.hadoop.fs.RawLocalFileSystem.pathToFile(RawLocalFileSystem.java:55)
at org.apache.hadoop.fs.LocalFileSystem.pathToFile(LocalFileSystem.java:61)
at org.apache.hadoop.fs.LocalFileSystem.exists(LocalFileSystem.java:51)
at org.apache.hadoop.fs.FileUtil.checkDest(FileUtil.java:355)
at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:211)
at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:163)
at org.apache.hadoop.fs.LocalFileSystem.copyFromLocalFile(LocalFileSystem.java:67)
at org.apache.hadoop.fs.FileSystem.copyFromLocalFile(FileSystem.java:1178)
at com.lango.mapreduce.example.chainmapper.Test.fsCopy(Test.java:32)
at com.lango.mapreduce.example.chainmapper.Test.main(Test.java:25)
1、Wrong FS: hdfs://master:9000/index.html, expected: file:///
a、解决方案:复制core-site.xml和hdfs-site.xml到当前工程下
因为是访问远程的HDFS, 需要通过URI来获得FileSystem:
hadoop需要把集群上的core-site.xml和hdfs-site.xml放到当前工程下(eclipse工作目录的bin文件夹下面)
注意:
在我的Eclipse工作目录中没有找到bin文件夹。
网上资料说“生成的class文件在项目目录中的bin目录下”,具体说法见下段参考资料:
生成的class文件在你的项目目录中的bin目录下,进入你的项目目录,可以看到一个.classpath文件,其中源文件地址,class文件存放地址,以及环境变量都是在这里面配置的,当然你可以通过myeclipse的界面配置,不过配置完成后都是修改的这个文件,<classpathentry kind="src" path="src"/>这个就是配置源文件存放地址,<classpathentry kind="lib" path="lib/activemq-console-4.1.1.jar"/>这些是将哪个目录的那个jar包导入到path中<classpathentry kind="output" path="classes"/>这个是生成的class文件存放到哪,其中目录可以为绝对目录,相对目录是相对当前目录来说的,也就是项目目录本身
所以,我觉得bin目录就是我目录结构中的build/classes文件。因此,拷贝core-site.xml和hdfs-site.xml到build/classes目录中。
再次运行之前的代码:
package com.lango.mapreduce.example.chainmapper;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class FsTest {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path src = new Path("C:/Users/lango/Desktop/core-site.xml");
Path dst = new Path("hdfs://master:9000/qj");
fs.copyFromLocalFile(src, dst);
}
}
运行通过。文件成功上传,问题解决。
2、问题引申:通过几种对文件操作方式的比较,来总结对于把文件上传到远程客户端什么是最关键的因素。
b、拷贝core-site.xml和hdfs-site.xml到当前工程下,修改目标路径形式为如下形式:
//注意和“Path dst = new Path("hdfs://master:9000/qj");”形式区分
Path dst = new Path("/qj");
整体代码如下:
package com.lango.mapreduce.example.chainmapper;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CopyToHDFS {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
fs.copyFromLocalFile(new Path("/home/wqj/opt/140702152709log.txt"), new Path("/qj"));
}
}
程序运行正常,文件上传成功。
c、不拷贝core-site.xml和hdfs-site.xml到当前工程下。配置
conf.set("fs.default.name", "hdfs://master:9000");
直接使用FileSystem类实现上传,代码如下:
package com.lango.mapreduce.example.chainmapper;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CopyToHDFS {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://master:9000");
FileSystem fs = FileSystem.get(conf);
fs.copyFromLocalFile(new Path("/home/wqj/opt/140702152709log.txt"), new Path("/qj"));
}
}
运行通过,文件上传到远程HDFS上成功。
d、拷贝core-site.xml和hdfs-site.xml到当前工程下。直接使用FileSystem类实现上传,代码如下:
package com.lango.mapreduce.example.chainmapper;
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 FsTest {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
fs.copyFromLocalFile(new Path("C:/Users/lango/Desktop/core-site.xml"), new Path("/qj-dfs"));
}
}
运行通过,文件成功上传。
e、不拷贝core-site.xml和hdfs-site.xml到当前工程下。直接使用FileSystem类实现上传,代码和b完全相同。
和b做对比,有一个奇妙的现象。
我们上传的文件它并没有被上传到远程HDFS中,而是跑到本地Eclipse工作目录所在根目录E盘下了。并且可看见文件的存放形式:.qj.crc和qj。
Eclipse控制台输出日志信息如下:
八月 12, 2014 2:47:41 下午 org.apache.hadoop.util.NativeCodeLoader <clinit>
WARNING: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
运行通过,文件未成功上传到远程HDFS中,而是被上传到Eclipse工作目录所在根目录下了。
f、不拷贝core-site.xml和hdfs-site.xml到当前工程下。直接使用DistributedFileSystem类实现上传,代码如下:
package com.lango.mapreduce.example.chainmapper;
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 FsTest {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://master:9000");
DistributedFileSystem fs = (DistributedFileSystem) FileSystem.get(conf);
Path src = new Path("C:/Users/lango/Desktop/core-site.xml");
Path dst = new Path("/qj-dfs");
fs.copyFromLocalFile(src, dst);
}
}
运行通过,文件成功上传。
注意:在d中,若省略“
conf.set("fs.default.name", "hdfs://master:9000");
”则程序报错。报错信息
Exception in thread "main" java.lang.ClassCastException: org.apache.hadoop.fs.LocalFileSystem cannot be cast to org.apache.hadoop.hdfs.DistributedFileSystem
at com.lango.mapreduce.example.chainmapper.FsTest.main(FsTest.java:16)
解决方案:拷贝core-site.xml和hdfs-site.xml到当前工程下。整体代码不改变,代码如下:
package com.lango.mapreduce.example.chainmapper;
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 FsTest {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
// 省略fs.default.name配置
// conf.set("fs.default.name", "hdfs://master:9000");
DistributedFileSystem fs = (DistributedFileSystem) FileSystem.get(conf);
Path src = new Path("C:/Users/lango/Desktop/core-site.xml");
Path dst = new Path("/qj-dfs");
fs.copyFromLocalFile(src, dst);
}
}
运行通过,文件上传成功。
通过上面一系列自己都觉得很晕的比较之后,感觉,无论怎么变,它们之间的最大区别就在于
fs.default.name属性的配置
conf.set("fs.default.name", "hdfs://master:9000");
综上所述:
无论我们是在代码中对"fs.default.name"进行配置,还是直接拷贝core-site.xml和hdfs-site.xml到当前工程下,最终我们的目的都是要实现对fs.default.name的配置。
只有对fs.default.name成功配置后,我们才能成功上传文件到远程客户端。