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)
因为是访问远程的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); } }
运行通过。文件成功上传,问题解决。
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成功配置后,我们才能成功上传文件到远程客户端。