BigData-05:HDFS上传与下载原理

本文深入探讨HDFS的常用操作,包括权限设置、文件上传下载、快照、回收站及配额管理,并解析HDFS的底层原理如RPC与代理对象,以及安全模式和副本率的管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


课程回顾:
(1)HDFS Web Console
(2)HDFS 命令操作(hdfs dfs–普通操作命令 hdfs dfsadmin 管理员命令)
(3)IDEA Maven 文件夹的创建。


1、HDFS权限问题
针对用户操作没有权限 permission denied:
(1)修改hdfs-site.xml 去掉权限检查(关闭HDFS服务 stop-all.sh;修改后 重新 Start-all.sh

     <property>
           <name>dfs.permissions</name>
           <value>false</value>
    </property>

(2)通过设定用户名字 root
System.setProperty("HADOOP_USER_NAME","root");
(3)通过java的-D参数传递。 HADOOP_USER_NAME=root (命令行的方式)
public static void main(String[] args)
https://www.cnblogs.com/-wangjiannan/p/3626965.html
(4)hdfs dfs -chmod 777 /input 让所有用户访问。
(5)针对HDFS权限问题,有kerberos认证。
Kerberos: The Network Authentication Protocol
https://www.cnblogs.com/wukenaihe/p/3732141.html
2、IDEA Maven工程实现HDFS的文件上传与下载

Maven环境中 只有当 POM文件中所有的依赖包全部变成白色。

(1)HDFS文件上传
查看源码:crtl+鼠标左键
## Failed to locate the winutils binary in the hadoop binary path java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries. ##
step1:
下载:hadoop2.7.3 winutils binary
https://github.com/rucyang/hadoop.dll-and-winutils.exe-for-hadoop2.7.3-on-windows_X64
step2: 配置环境变量 拷贝进入 D:\hadoop-2.7.3\bin文件下。
hadoop.home.dir —bin/winutils.exe
HADOOP_HOME:D:\hadoop-2.7.3,然后再path里面增加 %HADOOP_HOME%\bin
或者:System.setProperty("hadoop.home.dir", "D:\\hadoop-2.7.3");
(2)HDFS文件下载
使用IOUtils 输入路径 输出路径
IOUtils.copyBytes(input,output,1024);
3、HDFS上传与下载原理
(1)上传原理在这里插入图片描述
在这里插入图片描述在这里插入图片描述
https://www.processon.com

(2)下载原理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(3)nameNode工作机制:
在这里插入图片描述
(4)datanode工作机制:
在这里插入图片描述
4、安全模式 safe mode

检查副本率是否满足配置要求。副本率不够的时候,会水平复制,当下次那个挂掉的节点如果又活过来的话,副本数就会超过N了,就超了,系统会自动选一个多余的副本删掉
(1)冗余度:dfs.replication 3.有几个冗余的副本。
hdfs-site.xml

    <!--注释配置数据块的冗余度,默认是3-->
     <property>
            <name>dfs.replication</name>
            <value>1</value>
     </property>

(2)副本率:数据块实际冗余度(M),HDFS配置的数据块应该具有的冗余度(N),
M/N*100%;
例如:知否知否.avi M=2;HDFS配置的 N=3;
2/3=0.667。要求的副本率为 0.99,系统会水平复制数据块到其他节点。
如果是副本率过高,M=6,N=3,副本率=2;大于0.99.系统会删除多余的数据块。
在安全模式下 无法操作HDFS,因为正在进行副本率的检查工作。
进入或查看安全模式的命令:
hdfs dfsadmin -safemode get/enter/leave/wait
5、快照:是一种备份,默认:HDFS快照是关闭
## 一般不建议使用。 ##
快照的本质:将需要备份的数据放到一个隐藏目录下。
(1)开启和关闭快照:
hdfs dfsadmin -allowSnapshot <snapshotDir>
hdfs dfsadmin -disallowSnapshot
hdfs lsSnapshottableDir 查看开启快照的所有文件夹
(2)创建快照:
需要创建快照的目录 快照目录的名字
hdfs dfs -createSnapshot /folder111 backup_folder111_20190118
快照打出的日志:
Created snapshot /folder111/.snapshot/backup_folder111_20190118
(3)删除快照
hdfs dfs -deleteSnapshot /folder111 backup_folder111_20190118
(4)恢复快照:
hdfs dfs -cp /folder111/.snapshot/backup_folder111_20190118/a.png /folder111

6、回收站:默认HDFS的回收站禁用
(1)回收站的配置:
core-site.xml fs.trash.interval(时间间隔 分钟)
关闭集群后才能起作用。
(2)本质是剪切:回收站开启之后,会把删除的文件放到一个/user/root/.Trash/Current
(3)回收站回复也就是粘贴的过程。
7、配额:Quota
(1)名称配额
限定HDFS目录下,存放文件(目录)的个数>1,最多存放N-1个。
setQuota–指定名称配额
clrQuota–清除名称配额
例如:

  hdfs dfs -mkdir /myquota1
  hdfs dfsadmin -setQuota 3 /myquota1
  hdfs dfs -put ~/test.txt  /myquota1----第1个
  hdfs dfs -put ~/students.txt /myquota1--第2个。
  hdfs dfs -put ~/students01.txt /myquota1---第3个 无法放。
  ```
错误:put: The NameSpace quota (directories and files) of directory /myquota1 is exceeded: quota=3 file count=4
(2)空间配额	--必须要大于 默认数据块大小。
setSpaceQuota
clrSpaceQuota

8、HDFS底层原理-RPC
Remote Procedure Call:远程过程调用,调用代码不在本地执行,实现调用者与被调用者之间的连接和通信。
 基于Client server,相当于 DFSClient 相当于客户端。Namenode集群相当于Server。
9、HDFS底层原理-代理对象Proxy
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190227152811796.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaXlhbmFmZmVjdGlvbg==,size_16,color_FFFFFF,t_70)
(1)代理---明星的经纪人
  是一种设计模式,提供了对目标对象的另一种访问方式。通过代理对象访问目标对象。
(2)代理分为静态代理和动态代理。
  a、静态代理:接口的定义 实现接口。被代理对象与对象实现相同的接口。
  # b、动态代理:接口的定义 不需要实现接口(匿名内部类+反射 invoke) #
10、RPC与Proxy程序示例
 
  针对log4j warn
  	log4j:WARN No appenders could be found for logger (org.apache.hadoop.metrics2.lib.MutableMetricsFactory).
  	log4j:WARN Please initialize the log4j system properly.
  	log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
  可以在src/resource/通过 增加 log4j.properties解决。

RPC代码实例:
客户端:

package day0905.rpc.client;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;

import day0905.rpc.server.MyInterface;

public class MyRPCClient {

	public static void main(String[] args) throws Exception {
		// 使用Hadoop RPC的框架调用Server 端的程序
		/*
		RPC.getProxy(protocol,    调用的接口
				     clientVersion, 版本号
				     addr,   RPC Server的地址
				     conf)
		*/

		//得到的是Server端部署对象的代理对象
		MyInterface proxy = RPC.getProxy(MyInterface.class, 
							             MyInterface.versionID, 
							             new InetSocketAddress("localhost", 7788), 
							             new Configuration());
		
		//使用这个代理对象调用Server的程序
		String result = proxy.sayHello("Tom");
		System.out.println(result);
	}
}

服务端:

package day0905.rpc.server;

import org.apache.hadoop.ipc.VersionedProtocol;

public interface MyInterface extends VersionedProtocol{

	//定义一个版本号
	//使用版本号来进行签名
	public static long versionID = 1;
	
	//定义我们业务方法
	public String sayHello(String name);
}

package day0905.rpc.server;

import java.io.IOException;

import org.apache.hadoop.ipc.ProtocolSignature;

public class MyInterfaceImpl implements MyInterface {

	@Override
	public String sayHello(String name) {
		System.out.println("*********调用到了Server 端**********");
		return "Hello "+name;
	}

	@Override
	public ProtocolSignature getProtocolSignature(String arg0, long arg1, int arg2) throws IOException {
		//通过版本号定义签名信息
		return new ProtocolSignature(MyInterface.versionID, null);
	}

	@Override
	public long getProtocolVersion(String arg0, long arg1) throws IOException {
		//返回版本号
		return MyInterface.versionID;
	}
}
package day0905.rpc.server;

import java.io.IOException;

import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RPC.Server;

public class MyRPCServer {

	public static void main(String[] args) throws Exception {
		// 利用Hadoop RPC的框架实现RPC Server
		
		//使用RPC Builder来构建 
		RPC.Builder builder = new RPC.Builder(new Configuration());
		
		//定义Server的参数
		builder.setBindAddress("localhost");
		builder.setPort(7788);
		
		//部署我们的程序
		builder.setProtocol(MyInterface.class); //部署的接口
		builder.setInstance(new MyInterfaceImpl()); //指定接口的实现类
		
		// 创建RPC Server
		Server server = builder.build();
		
		//启动Server
		server.start();
	}
}

HDFS上传与下载API的使用:

package com.itstar.hunter.demo01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.junit.Before;
import org.junit.Test;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

public class HDFSClient {

    private FileSystem fs = null;

    /**
     * 加载配置
     * @throws URISyntaxException
     * @throws IOException
     * @throws InterruptedException
     */
    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        // 1. 加载配置文件
        Configuration conf = new Configuration();

        // 2. 指定副本个数
        conf.set("dfs.replication", "2");

        // 3. 指定块大小
        conf.set("dfs.blocksize", "64m");

        // 4. 构造客户端
        fs = FileSystem.get(new URI("hdfs://192.168.100.100:9000/"), conf, "root");

    }

    /**
     * 在hdfs中创建文件夹: hdfs dfs -mkdir /文件名
     */
    @Test
    public void hdfsMkfir() throws IOException {
        // 1.调用方法创建文件夹
        fs.mkdirs(new Path("/newDir"));

        // 2. 关闭资源
        fs.close();
    }

    /**
     * 在hdfs中 移动/修改 文件
     */
    @Test
    public void hdfsRename() throws IOException {
        //1.调用移动并修改
        fs.rename(new Path("/hello.txt"), new Path("newDir/file.txt"));
        // 2. 关闭资源
        fs.close();
    }

    /**
     * 在hdfs中删除文件夹
     * hdfs dfs -rm -r /
     */
    @Test
    public void hdfsRm() throws IllegalArgumentException, IOException {
        //fs.delete(new Path("/hunterhenshuai"));
        //1.调用删除文件方法 参数1:删除的路径 参数2:是否递归删除
        fs.delete(new Path("/hello.txt"), true);
        fs.close();
    }


    /**
     * 查询hdfs下制定的目录信息
     */
    @Test
    public void hdfsLs() throws IOException {
        // 1. 调用方法,返回远程迭代器
        RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"),true);

        // 2. 取迭代器数据
        while (files.hasNext()){

            // 3. 拿数据
            LocatedFileStatus status = files.next();
            System.out.println("文件的路径为:" + status.getPath());
            System.out.println("块大小为" + status.getBlockSize());
            System.out.println("文件长度为:" + status.getLen());
            System.out.println("副本数量为:" + status.getReplication());
            System.out.println("块信息为:" + Arrays.toString(status.getBlockLocations()));

            System.out.println("===============================");
        }

        //3.关闭资源
        fs.close();
    }

    /*
     * 判断文件还是文件夹
     */
    @Test
    public void findAtHdfs() throws FileNotFoundException, IllegalArgumentException, IOException {
        // 1. 展示文件状态信息
        FileStatus[] files = fs.listStatus(new Path("/"));

        // 2. 遍历所有文件
        for (FileStatus file : files) {
            if (file.isFile()) {
                //文件
                System.out.println("文件----f----" + file.getPath().getName());
            } else {
                //文件夹
                System.out.println("文件----d----" + file.getPath().getName());
            }
        }
    }

}

/**
     * 上传文件
     */
    @Test
    public  void test1() {
        // 1. 加载配置文件
        Configuration conf = new Configuration();

        // 2. 指定副本个数
        conf.set("dfs.replication", "2");

        // 3. 指定块大小
        conf.set("dfs.blocksize", "64m");

        // 4. 构造客户端
        FileSystem fs = null;
        try {
            fs = FileSystem.get(new URI("hdfs://192.168.100.100:9000/"), conf, "root");

            // 5. 上传文件
            fs.copyFromLocalFile(new Path("C:/Users/think/Desktop/excel.xlsx"), new Path("/aaaaaa.xlsx"));

            fs.close();
        } catch (IOException | URISyntaxException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 下载文件
     * @throws URISyntaxException
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    public void test2() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf = new Configuration();

        conf.set("dfs.replication", "2");
        conf.set("dfs.blocksize", "64m");
        FileSystem fs = FileSystem.get(new URI("hdfs://192.168.100.100:9000/"), conf, "root");
        // 5.hdfs数据下载到windows本地
        fs.copyToLocalFile(new Path("/girl.txt"), new Path("C:/Users/think/Desktop/"));
        fs.close();
    }
public class HdfsIO {
    private Configuration conf = null;
    FileSystem fs = null;

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        conf = new Configuration();
        fs = FileSystem.get(new URI("hdfs://192.168.100.100:9000/"), conf, "root");
    }

    /**
     * 上传文件
     * @throws IOException
     */
    @Test
    public void putFileToHDFS() throws IOException {
        // 1. 获取输入流
        FileInputStream inputStream = new FileInputStream(new File("C:/Users/think/Desktop/count/words.txt"));

        // 2. 获取输出流
        FSDataOutputStream outputStream = fs.create(new Path("/test1"));

        // 3. 流的拷贝
        IOUtils.copyBytes(inputStream, outputStream, conf);

        // 4. 关闭资源
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(outputStream);
    }

    /**
     * 文件下载
     */
    @Test
    public void getFileFromHDFS() throws IOException {
        // 1.获取输入流
        FSDataInputStream inputStream = fs.open(new Path("/data.xlsx"));
        // 2. 获取输出流
        FileOutputStream outputStream = new FileOutputStream(new File("C:/Users/think/Desktop/new.txt"));
        // 3. 流的拷贝
        IOUtils.copyBytes(inputStream, outputStream, conf);

        // 4. 关闭资源
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(outputStream);
    }
}
public class ReadData {

    private FileSystem fs = null;

    /**
     * 加载配置
     * @throws URISyntaxException
     * @throws IOException
     * @throws InterruptedException
     */
    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        // 1. 加载配置文件
        Configuration conf = new Configuration();

        // 2. 构造客户端
        fs = FileSystem.get(new URI("hdfs://192.168.100.100:9000/"), conf, "root");
    }


    /**
     * 读数据方式一
     * @throws IOException
     */
    @Test
    public void testReadData() throws IOException {
        FSDataInputStream inputStream = fs.open(new Path("/girl.txt"));

        byte[] buff = new byte[1024];
        inputStream.read(buff);
        System.out.println(new String(buff));
        inputStream.close();
        fs.close();
    }

    /**
     * 读数据方式二
     */
    @Test
    public void testReadData2() throws IOException, IllegalArgumentException {
        // 1. 拿到文件流
        FSDataInputStream inputStream = fs.open(new Path("/girl.txt"));

        // 2. 缓冲流
        //2.缓冲流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));

        // 3. 按行读取
        String line = null;
        while ((line = bufferedReader.readLine()) != null){
            System.out.println(line);
        }

        // 4. 关闭资源
        bufferedReader.close();
        inputStream.close();
        fs.close();
    }


    /**
     * 读取hdfs中指定偏移量
     */
    @Test
    public void testRandomRead() throws IOException {
        //1.拿到流
        FSDataInputStream in = fs.open(new Path("/hello.txt"));

        in.seek(14);

        byte[] b = new byte[5];

        in.read(b);

        System.out.println(new String(b));

        in.close();
    }

    /*
     * 在hdfs中写数据
     */
    @Test
    public void testWriteData() throws IllegalArgumentException, IOException {
        //1.输出流
        FSDataOutputStream out = fs.create(new Path("/love.txt"), false);

        //2.输入流
        FileInputStream in = new FileInputStream("C:/Users/think/Desktop/lovable.txt");

        byte[] buf = new byte[1024];

        int read = 0;

        while((read = in.read(buf)) != -1) {

            out.write(buf, 0, read);
        }

        in.close();
        out.close();
        fs.close();
    }

    /*
     * 在hdfs中写数据
     */
    @Test
    public void testWriteData1() throws IllegalArgumentException, IOException {
        //1.创建输出流
        FSDataOutputStream out = fs.create(new Path("/feiyan"));

        //2.创建输入流
        FileInputStream in = new FileInputStream(new File("C:/Users/think/Desktop/lovable.txt"));

        //3.写数据
        out.write("l want have a girlfriend.".getBytes());

        //4.关闭资源
        IOUtils.closeStream(out);
        fs.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

phial03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值