今天学习了hadoop中的java api的简单使用,这篇文章就记录一下今天的学习成果。

hadoop中java编程的基本套路就是需要先实例化一个FileSystem,因为每一次操作都要用到这个FileSystem,所以我们就将这部分代码抽取出来,写到一个工具类里。
Util.java

public class Util {

    private  Configuration conf;
    private  String hdfsPath = "hdfs://192.168.228.141:9000";
    private  FileSystem fs;

    //空参数构造函数
    Util(){

    }

    //修改hdfsPath的构造函数
    Util(String hdfsPath){
        this.hdfsPath = hdfsPath;
    }

    //修改conf的构造函数
    Util(Configuration conf){
        this.conf = conf;
    }

    //两个都修改的构造函数
    Util(String hdfsPath, Configuration conf){
        this.hdfsPath = hdfsPath;
        this.conf = conf;
    }

    public  FileSystem getfs(){
        this.conf = new Configuration();
        try {
            fs = FileSystem.get(new URI(this.hdfsPath), this.conf);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return this.fs;
    }

    public Configuration getConf() {
        return conf;
    }

    public void setConf(Configuration conf) {
        this.conf = conf;
    }

    public String getHdfsPath() {
        return hdfsPath;
    }

    public void setHdfsPath(String hdfsPath) {
        this.hdfsPath = hdfsPath;
    }

    public FileSystem getFs() {
        return fs;
    }

    public void setFs(FileSystem fs) {
        this.fs = fs;
    }

}

其中hdfsPath应该写自己的hadoop集群中namenode的ip地址,默认端口号为9000。
有了这个工具类之后,我们在之后的操作中只需要获取一次FileSystem就可以一直使用了。
下面我们来封装hadoop中java api。
首先是创建文件

// 创建文件,并且写入data
    /*
        状态码:1代表写入成功,0代表写入不成功,有异常抛出,-1代表文件存在
    */
    public int createFile(String filename, String data){
        try {
            boolean exist = this.fs.exists(new Path(filename));
            if(exist){
                System.out.println("文件已经存在,创建失败");
                return -1;  //文件存在
            }
            FSDataOutputStream outputStream = this.fs.create(new Path(filename));
            byte[] buff = data.getBytes();
            outputStream.write(buff, 0, buff.length);
            outputStream.close();
            System.out.println("文件创建成功,并且已经写入数据");
            outputStream.close();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }
// 创建文件,不写入内容
    /*
        状态码:1代表写入成功,0代表写入不成功,有异常抛出,-1代表文件存在
    */
    public int createFile(String filename){
        try {
            boolean exist = this.fs.exists(new Path(filename));
            if(exist){
                System.out.println("文件存在,创建失败");
                return -1;  //文件存在
            }
            FSDataOutputStream outputStream = this.fs.create(new Path(filename));
            System.out.println("创建文件成功,没有写入任何数据");
            outputStream.close();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

接着是删除文件

//删除文件
    /*
    * 状态码:1代表删除成功,0代表删除失败
    * */
    public int deleteFile(String filename){
        try {
            boolean exist = fs.exists(new Path(filename));
            if(exist==false){
                System.out.println("文件不存在,删除失败");
                return 0;
            }
            boolean result = fs.delete(new Path(filename), true);
            if(result){
                return 1;
            } else {
                return 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;

    }

接着是创建目录

//创建目录
    /*
    * 状态码:1代表创建成功,0代表创建失败
    * */
    public int mkdirs(String dir){
        try {
            boolean exist = fs.exists(new Path(dir));
            if (exist) {
                System.out.println("文件夹存在,创建失败");
                return 0;
            }
            boolean result = fs.mkdirs(new Path(dir));
            if(result){
                System.out.println("创建成功");
                return 1;
            } else {
                System.out.println("创建失败");
                return 0;
            }
        } catch (IOException e){
            e.printStackTrace();
        }
        return 0;
    }

接着是读取文件并显示

//读取文件
    /**
     * 状态码:1代表读取成功,0代表读取失败
     * */
    public int readFile(String filename){
        try {
            boolean exist = fs.exists(new Path(filename));
            if (!exist){
                System.out.println("文件不存在,读取失败");
                return 0;
            }
            FSDataInputStream inputStream = fs.open(new Path(filename));
            BufferedReader buff = new BufferedReader(new InputStreamReader(inputStream));
            String line = null;
            while((line=buff.readLine())!=null){
                System.out.println(line);
            }
            inputStream.close();
            return 1;
        } catch (IOException e){
            e.printStackTrace();
        }
        return 0;
    }

接着是上传本地文件到hadoop

//从本地上传文件到hadoop
    public int upload(String localdir, String remotedir){
        try {
            fs.copyFromLocalFile(new Path(localdir), new Path(remotedir));
            System.out.println("上传成功,上传到:" + remotedir);
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 1;
    }

接着是从hadoop下载文件到本地,这个函数里面我没有直接使用java api,而是使用FileSystem打开文件,然后使用IOUtils进行二进制数据复制,原因是使用java api的时候总是报错,索性自己写了,经过测试,可以下载文本文件,也可以下载图片。

//从hadoop上下载文件到本地
    public int download(String localdir, String remotedir){

        try {
            //获取本地文件路径
            String[] remotefilename = remotedir.split("/");
            String filename = localdir+remotefilename[remotefilename.length-1];

            //从hadoop上读取文件
            FSDataInputStream inputStream = fs.open(new Path(remotedir));
            //在本地创建相应文件
            File file = new File(filename);
            FileOutputStream localFile = new FileOutputStream(file);
            //下面进行二进制复制
            IOUtils.copyBytes(inputStream, localFile, 2048, true);
            System.out.println("文件下载完成:"+filename);
            inputStream.close();
            localFile.close();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            e.printStackTrace();
        }
        return 0;
    }

最后是查看给定目录下的所有文件,使用递归的方式,有点慢

//查看目录下所有文件
    public void getdirs(String dir){
        try {
            FileStatus[] status = fs.listStatus(new Path(dir));
            for (FileStatus fileStatus : status) {
                if(fileStatus.isDirectory()){
                    System.out.println("d :"+fileStatus.getPath().toString());
                } else {
                    System.out.println("f :"+fileStatus.getPath().toString());
                }

                if(fileStatus.isDirectory()){
                    getdirs(fileStatus.getPath().toString());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

在学习的过程中,我遇到了两个问题,这里记录一下。

第一个问题是在win10下访问不到ubuntu虚拟机上的hadoop集群

解决的方法是修改hadoop/etc/hadoop/core-site.xml中的url,将原来的localhost修改成了hadoop-allow,并且在**/etc/hosts中添加一条ip映射0.0.0.0 hadoop-allow**,这样就代表所有人都可以访问到hadoop集群的9000端口。

在linux命令行中输入 netstat -tpnl,当现实内容如下的时候就说明任何主机都可以正常访问hadoop了

使用java api操作hdfs hadoop java api_hdfs


主要就是要看9000端口对应的是0.0.0.0还是127.0.0.1。学过计算机网络的同学应该都还记得0.0.0.0代表默认ip地址,127.0.0.1代表本主机,是个回环地址。

第二个问题是在ubuntu关机重启后datanode不工作了
使用50070界面查看不到datanode,解决的方法比较暴力,就是将hadoop/etc/hadoop/hdfs-site.xml文件中设置的路径删除,然后重新创建,创建完成后使用 hadoop namenode -format 初始化之后就可以正常使用了。这个问题的原理我不懂,如果有懂的同学欢迎在下面留言告诉我。

最后放上完整的代码
hdfsAPI.java

import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;



import java.io.*;

//这个类写hdfs中的各种操作
public class hdfsAPI {


    public static void main(String[] args) {

        hdfsAPI api = new hdfsAPI();
        api.getdirs("/input");


    }

    private FileSystem fs;

    hdfsAPI(){
        this.fs = new Util().getfs();
    }

    // 创建文件,并且写入data
    /*
        状态码:1代表写入成功,0代表写入不成功,有异常抛出,-1代表文件存在
    */
    public int createFile(String filename, String data){
        try {
            boolean exist = this.fs.exists(new Path(filename));
            if(exist){
                System.out.println("文件已经存在,创建失败");
                return -1;  //文件存在
            }
            FSDataOutputStream outputStream = this.fs.create(new Path(filename));
            byte[] buff = data.getBytes();
            outputStream.write(buff, 0, buff.length);
            outputStream.close();
            System.out.println("文件创建成功,并且已经写入数据");
            outputStream.close();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    // 创建文件,不写入内容
    /*
        状态码:1代表写入成功,0代表写入不成功,有异常抛出,-1代表文件存在
    */
    public int createFile(String filename){
        try {
            boolean exist = this.fs.exists(new Path(filename));
            if(exist){
                System.out.println("文件存在,创建失败");
                return -1;  //文件存在
            }
            FSDataOutputStream outputStream = this.fs.create(new Path(filename));
            System.out.println("创建文件成功,没有写入任何数据");
            outputStream.close();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }


    //删除文件
    /*
    * 状态码:1代表删除成功,0代表删除失败
    * */
    public int deleteFile(String filename){
        try {
            boolean exist = fs.exists(new Path(filename));
            if(exist==false){
                System.out.println("文件不存在,删除失败");
                return 0;
            }
            boolean result = fs.delete(new Path(filename), true);
            if(result){
                return 1;
            } else {
                return 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;

    }


    //创建目录
    /*
    * 状态码:1代表创建成功,0代表创建失败
    * */
    public int mkdirs(String dir){
        try {
            boolean exist = fs.exists(new Path(dir));
            if (exist) {
                System.out.println("文件夹存在,创建失败");
                return 0;
            }
            boolean result = fs.mkdirs(new Path(dir));
            if(result){
                System.out.println("创建成功");
                return 1;
            } else {
                System.out.println("创建失败");
                return 0;
            }
        } catch (IOException e){
            e.printStackTrace();
        }
        return 0;
    }


    //读取文件
    /**
     * 状态码:1代表读取成功,0代表读取失败
     * */
    public int readFile(String filename){
        try {
            boolean exist = fs.exists(new Path(filename));
            if (!exist){
                System.out.println("文件不存在,读取失败");
                return 0;
            }
            FSDataInputStream inputStream = fs.open(new Path(filename));
            BufferedReader buff = new BufferedReader(new InputStreamReader(inputStream));
            String line = null;
            while((line=buff.readLine())!=null){
                System.out.println(line);
            }
            inputStream.close();
            return 1;
        } catch (IOException e){
            e.printStackTrace();
        }
        return 0;
    }


    //从本地上传文件到hadoop
    public int upload(String localdir, String remotedir){
        try {
            fs.copyFromLocalFile(new Path(localdir), new Path(remotedir));
            System.out.println("上传成功,上传到:" + remotedir);
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 1;
    }

    //从hadoop上下载文件到本地
    public int download(String localdir, String remotedir){

        try {
            //获取本地文件路径
            String[] remotefilename = remotedir.split("/");
            String filename = localdir+remotefilename[remotefilename.length-1];

            //从hadoop上读取文件
            FSDataInputStream inputStream = fs.open(new Path(remotedir));
            //在本地创建相应文件
            File file = new File(filename);
            FileOutputStream localFile = new FileOutputStream(file);
            //下面进行二进制复制
            IOUtils.copyBytes(inputStream, localFile, 2048, true);
            System.out.println("文件下载完成:"+filename);
            inputStream.close();
            localFile.close();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            e.printStackTrace();
        }
        return 0;
    }

    //查看目录下所有文件
    public void getdirs(String dir){
        try {
            FileStatus[] status = fs.listStatus(new Path(dir));
            for (FileStatus fileStatus : status) {
                if(fileStatus.isDirectory()){
                    System.out.println("d :"+fileStatus.getPath().toString());
                } else {
                    System.out.println("f :"+fileStatus.getPath().toString());
                }

                if(fileStatus.isDirectory()){
                    getdirs(fileStatus.getPath().toString());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


}

读取目录函数的输出如下

使用java api操作hdfs hadoop java api_hadoop_02


那么这篇文章就写到这里啦,希望能帮到你_