Hadoop入门--HDFS

HDFS 的使用场景: 适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭 之后就不需要改变。

HDFS优点:

  • 高容错。
  • 适合处理大规模数据。
  • 可构建在廉价机器上。

HDFS缺点

  • 相比其它文件系统访问数据速度更慢。

  • HDFS不适合存取大量小文件,每个文件会占用NameNode150字节的内存,128G内存的NameNode能存取9亿个文件;检索时间超过了读取时间。

  • HDFS不支持并发写入,且仅支持数据追加,不支持文件随机修改。

HDFS Block

HDFS按block存储,blocksize可以另外设置,Hadoop3.x默认128MB。

HDFS读取数据时间(rt) = 数据块寻址时间(at) + 磁盘传输数据时间(tt)

若blocksize太小,一个文件会被分成多个数据块存储,读数据需要进行多次寻址,此时at较大

若blocksize太大,没办法有效的利用并发寻找数据块的性能,此时tt较大

合理的blocksize大小取决于磁盘传输速率,通常机械硬盘设置128MB,固态硬盘设置为256MB。

HDFS备份数

一般的分布式集群中多台服务器作为DataNode,可以自定义HDFS中文件的备份数,若有三个DataNode则最多可以备份三份。

若备份数设置大于三,则集群中增加服务器数量时可以自动备份;

若备份数设置小于三,则集群会选择最近的节点进行数据备份;

在我们之前搭建的单节点伪分布式集群中,实际只能备份一份在localhost,查找该备份的方法在之前的文章中有介绍过。

HDFS API操作

  • 获取客户端对象
  • 执行api操作
  • 关闭资源

Demo中尝试使用了JUnit单元测试,@Test注释了待测试的代码块,@Before注释的方法为@Test之前执行的代码块,@After注释的方法为@Test之后执行的代码块。之前在学校做项目没做过类似的单元测试,都直接写完功能做整体的系统测试了,但其实开发流程规范化也是十分重要的。

public class HdfsClient {

    private FileSystem fs;

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        // 连接集群的NN地址
        URI uri = new URI("hdfs://localhost:9000");
        // 创建一个配置文件
        Configuration configuration = new Configuration();
        // configuration.set("dfs.replication","2");
        String user = "aaron";
        // 获取客户端对象
        fs = FileSystem.get(uri, configuration, user);

    }

    @After
    public void close() throws IOException {
        // 关闭资源
        fs.close();
    }
  
    @Test
  	/**
     * 待测试的代码块
     */
}

参数优先级排序:客户端代码中设置的值 > 项目资源目录下的配置文件 > 服务器的自定义配置(xxx-site.xml) > 服务器的默认配置(xxx-default.xml)

(1) 创建目录

@Test
public void testmkdir() throws IOException, URISyntaxException {
		fs.mkdirs(new Path("/xiyou/huaguoshan"));
} 

**弱智踩坑:**一开始URI uri = new URI(“hdfs://localhost:9000”)的hdfs后面没有打冒号,测试代码后,用Hadoop Shell和浏览NN的web页面发现都没有成功创建文件,尝试用list列出了根目录下全部文件的详细信息,发现访问的是本地文件系统并不是HDFS;错误虽然智障,但可以顺便阅读FileSystem.get方法源码。

String scheme = uri.getScheme();
String authority = uri.getAuthority();
if (scheme == null && authority == null) {
		return get(conf);
}

scheme是根据uri解析的协议名,authority是主机名。如果是正确uri,scheme将为hdfs,authority为localhost:9000;由于这里传入的uri不合法所以scheme为null,进入get(conf),将返回默认的文件系统;

public static FileSystem get(Configuration conf) throws IOException {
    return get(getDefaultUri(conf), conf);
}

public static URI getDefaultUri(Configuration conf) {
    URI uri = URI.create(fixName(conf.get("fs.defaultFS", "file:///")));
    if (uri.getScheme() == null) {
        throw new IllegalArgumentException("No scheme in default FS: " + uri);
    } else {
        return uri;
    }
}

默认的文件系统是file:///,即为本地的文件系统,这也解释了为什么之前list返回的都是本地文件系统根目录的文件。

(2) 上传:

@Test
public void testPut() throws IOException {
    // 参数一:是否删除原文件  参数二:是否允许覆盖  参数三:原文件路   径  参数四:目的地路径
		fs.copyFromLocalFile(false, false, 
            new Path("/Users/aaron/sunwukong.txt"),
    				new Path("/xiyou/huaguoshan"));
}

(3) 下载:

@Test
public void testGet() throws IOException {
    // 参数一:是否删除原文件  参数二:原文件路径  参数三:目标地址路径  参数四:是否开启CRC校验
    fs.copyToLocalFile(false, new Path("/xiyou/huaguoshan"), 
            new Path("/Users/aaron/"), false);
}

(4) 删除

@Test
public void testRm() throws IOException {
    // 参数一:待删除路径  参数二:是否递归删除
    fs.delete(new Path("/xiyou"), true);
}

注意如果参数一的路径下非空,参数二选择不递归删除会抛出非空异常。

(5) 更名和移动

@Test
public void testmv() throws IOException {
    // 参数一:原文件路径  参数二:目标文件路径
    // 修改文件名
    fs.rename(new Path("/jingguo/weiguo.txt"), new Path("/jingguo/wg.txt"));
    // 文件移动和更名
    fs.rename(new Path("/jingguo/wg.txt"), new Path("/weiguo.txt"));
    // 修改目录名
    fs.rename(new Path("/jingguo"), new Path("/sanguo"));
    // 目录的移动和更名
    fs.rename(new Path("/user/sanguo"), new Path("/sanguo"));
}

(6) 获取文件详细信息

@Test
public void fileDetail() throws IOException {
    RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/sanguo"), true);
    System.out.println(listFiles);
    while (listFiles.hasNext()) {
        LocatedFileStatus fileStatus = listFiles.next();
        System.out.println("========" + fileStatus.getPath() + "=========");
        System.out.println(fileStatus.getPermission());
        System.out.println(fileStatus.getOwner());
        System.out.println(fileStatus.getGroup());
        System.out.println(fileStatus.getLen());
        System.out.println(fileStatus.getModificationTime());
        System.out.println(fileStatus.getReplication());
        System.out.println(fileStatus.getBlockSize());
        System.out.println(fileStatus.getPath().getName());

        // 获取块信息
        BlockLocation[] blockLocations = fileStatus.getBlockLocations();
        System.out.println(Arrays.toString(blockLocations));
    }
}

(7) 判断是文件还是目录

@Test
public void testFile() throws IOException {
    FileStatus[] listStatus = fs.listStatus(new Path("/"));
    for (FileStatus fileStatus : listStatus) {
        if(fileStatus.isFile()) {
            System.out.println("文件:"+fileStatus.getPath().getName());
        } else {
            System.out.println("目录:"+fileStatus.getPath().getName());
        }
    }
}

参考:尚硅谷丨大数据Hadoop 3.x(2021全新升级/部署+源码+实战)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值