HDFS里文件操作的命令都是通过 hdfs dfs 和对文件操作的命令以及参数构成的。比如我们在Linux 里常用的 ls命令,在hdfs里就是 hdfs dfs -ls。因为hdfs还有很多对hdfs系统进行维护的命令,比如进行数据平衡命令(hdfs balancer ),images/edits 文件检查的命令,所以为了把文件操作命令独立开来,所以必须以hdfs dfs 来操作hdfs文件。

命令行操作

1.将本地文件复制到HDFS

put命令


hdfs dfs -put localfile /hadoopfile

2.将HDFS文件复制到本地

get命令


hdfs dfs -get /hadoopfile localfile

3.创建一个文件夹

mkdir命令


hdfs dfs -mkdir [-p] /hadooppath/dir

-p 参数会在父目录不存在的情况下创建父目录。

4.删除一个文件/文件夹

rm命令


hdfs dfs -rm [-f][-r] /hadooppath/dir

-f 会强制删除,不会出现警告提示。
-r 删除文件时会删除文件夹下所有内容。

5.修改文件的备份数

-setrep命令


hdfs dfs -setrep [-w] <备份数> <hadoop路径>

-w 表示等待命令执行完成。这个过程可能比较久
如果路径是个文件夹,则这个文件夹下的所有文件的备份数都会被改变。
可以看到对HDFS文件的操作和linux下对文件操作命令非常相似。这让我们很容易上手。更多命令可以参考Hadoop官方文档

Java对HDFS的操作

我们主要通过org.apache.hadoop.fs.FileSystem类来对HDFS进行访问。我们写的程序最好是编译成一个jar放到hadoop集群内部去执行,它的好处是:
1. 不需要进行Hadoop依赖的jar文件的设置。
2. 数据文件传输更高效。因为在同一个网络内部。

如果你需要在Hadoop集群外部通过Java对HDFS进行访问。

编译配置

程序编译你需要设置的Maven依赖是:


        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>3.0.0</version>
        </dependency>

运行配置
一个方便的办法是去HDFS集群的一个节点运行下边命令查看HDFS运行依赖的jar文件。


        hdfs classpath

将这些jar文件都拷贝到需要运行HDFS访问的机器上。并将这些jar都放到classpath里。如果你的程序是运行在Hadoop的节点上。你只要通过下边的命令来执行就可以:


        hadoop jar yourapp.jar mainclassname [args...]

Java 程序示例


package fun.rethink;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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;

public class HadoopDemo {
    FileSystem fs;
    public HadoopDemo(String hadoopPath) {
        System.setProperty("HADOOP_USER_NAME", "root");
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", hadoopPath);
        try {
            fs = FileSystem.get(conf);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void testWrite(String filePath) {
        Path p = new Path(filePath);
        FSDataOutputStream fsos=null;
        try {
            fsos = fs.create(p);
            for(int i =1;i<=1000;i++) {
                fsos.write((i+"\n").getBytes("UTF-8"));
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {
            if (fsos!=null) {
            try {
                fsos.hsync();
                fsos.close();
            }
            catch(Exception ex) {
                ex.printStackTrace();
            }
            }
        }
    }
   
    public void testRead(String filePath) {
        Path p = new Path(filePath);
        FSDataInputStream fsis=null;
        try {
            fsis = fs.open(p);
            InputStreamReader isr = new InputStreamReader(fsis);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while((line = br.readLine())!=null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {
            if(fsis!=null) {
                try {
                    fsis.close();
                }
                catch(IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        HadoopDemo hd =new HadoopDemo("hdfs://hadoop1:9000");
        hd.testWrite("/test/number");
        hd.testRead("/test/number");
    }

}

HDFS文件读写解析

文件读取


1.应用程序获得一个FileSystem的实例,并且通过Open方法去打开一个HDFS文件。
2.FileSystem通过我们的配置找到HDFS的NameNode,获取到我们要读取文件的开始的块,以及这些块所在的DataNode的地址列表。
3.应用程序通过FSDataInputStream去读取数据。
4.FSDataInputStream会根据DataNode地址去按顺序去获取DataNode里的数据块。
5.如果一个数据块读取完毕,会从NameNode获取文件下一个数据块做在的DataNode的地址,并且读取数据,这个对于应用程序是透明的。
6.应用程序关闭FSDataInputStream。

需要注意的是用户的程序是直接从DataNode获取数据,而不需要通过NameNode。

文件写入


1.应用程序获得一个FileSystem的实例,并且通过Create方法去创建一个HDFS文件。
2.FileSystem通过我们的配置找到HDFS的NameNode,申请创建一个文件。
3.应用程序通过FSDataOutputStream去写数据。
4.FSDataOutputStream会向NameNode请求一组DataNode,然后开始流式的写入过程。一个个小的数据包先写入DataNode1,接着流入DataNode2,然后到DataNode3。
5.DataNode3写入数据后返回,DataNode2返回,DataNode1返回,这时一个数据包才算写完。由于大部分时间3个dataNode都是在并行的写入数据,所以写3个Node和写1个Node时间区别不大。这也是流式写入的优势。
6.应用程序关闭FSDataOutputStream。
7.通知NameNode文件写入完成。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

%d 博主赞过: