Hadoop(十)HDFS API操作

一年都在冬眠發表於2024-09-14

API操作

  • Shell操作是在叢集內部,即hadoop102上進行操作,API操作是希望在Windows上能遠端連線叢集實現增刪改查操作

一、客戶端環境準備

1、找到資料包路徑下的Windows依賴資料夾,複製hadoop-3.1.0到非中文路徑
2、在Windows上配置HADOOP_HOME環境變數
3、配置Path環境變數
4、驗證Hadoop環境變數是否正常,雙擊winutils.exe,如果報錯,則可能缺少微軟執行庫
5、在IDEA中建立一個Maven工程HdfsClientDemo,並匯入相應的依賴座標+日誌新增

<dependencies>
	<dependency>
		<groupId>org.apache.hadoop</groupId>
		<artifactId>hadoop-client</artifactId>
		<version>3.1.3</version>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.7.30</version>
	</dependency>
</dependencies>
  • 在專案的src/main/resources目錄下,新建一個檔案,命名為“log4j.properties”,在檔案中填入:
log4j.rootLogger=INFO, stdout 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n 
log4j.appender.logfile=org.apache.log4j.FileAppender 
log4j.appender.logfile.File=target/spring.log 
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

6、建立包名:com.user.hdfs
7、建立HdfsClient類

package com.user.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;


public class HdfsClient {
    private FileSystem fs;

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        // 1 獲取檔案系統
        //連線的叢集地址
        URI uri = new URI("hdfs://hadoop102:8020");
        //建立一個配置檔案
        Configuration configuration = new Configuration();
        //使用者
        String user = "user";
        //獲取客戶端物件
        this.fs = FileSystem.get(uri, configuration, user);
    }

    @After
    public void close() throws IOException {
        // 3 關閉資源
        fs.close();
    }
    @Test
    public void testmkdirs() throws IOException, URISyntaxException, InterruptedException {
        // 2 建立目錄
        fs.mkdirs(new Path("/xiyou/huaguoshan1"));
    }
}

注意

  • 在以上程式碼中,獲取客戶端物件這麼寫FileSystem fs = FileSystem.get(uri, configuration, user);會丟擲丟擲NullPointerException,因為在@Before註解的init方法中,我們在方法內部建立了FileSystem的一個新例項,但是沒有將其賦值給類的成員變數fs。由於成員變數fs沒有被初始化,它仍然是null,所以在@After註解的close方法中呼叫fs.close()時會丟擲NullPointerException
  • 在HDFS Web端刪除檔案huaguoshan1報錯Permission denied: user=dr.who, access=WRITE, inode="/xiyou":user:supergroup:drwxr-xr-x表示使用者dr.who試圖對/xiyou目錄進行寫操作,但是沒有足夠的許可權,只好在hadoop102使用Shell命令刪除檔案

二、其他API案例實操

1、從本地上傳檔案

  • 首先在本地D盤建立一個文字檔案sunwukong.txt
  • 在上述HdfsClient類程式碼裡繼續新增如下程式碼,以下例項也一樣
// 上傳
    @Test
    public void testPut() throws IOException {
        //引數解讀
        //引數一:表示是否刪除原資料
        //引數二:表示是否允許覆蓋
        //引數三:原資料路徑
        //引數四:目的地路徑
        fs.copyFromLocalFile(false,false,new Path("D:\\sunwukong.txt"),new Path("/xiyou/huaguoshan"));
    }

注意引數優先順序

  • 引數優先順序從低到高:hdfs-default.xml —> hdfs-site.xml —> 在專案資源目錄下的配置檔案 —> 程式碼裡面的配置
  • 在上面的檔案上傳的程式碼中,沒有額外設定副本數,即Replication的值為3
  • 假設我們在專案資源目錄下新建檔案hdfs-site.xml並新增如下內容,那麼上傳檔案後顯示的Replication值為1
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
	<property>
		<name>dfs.replication</name>
		<value>1</value>
	</property>
</configuration>
  • 假設我們繼續在init方法中新增如下內容,則上傳檔案後的Replication值為2
configuration.set("dfs.replication", "2");

2、從HDFS下載檔案到本地

    // 檔案下載 從HDFS下載資料到本地
    @Test
    public void testGet() throws IOException {
        //引數一:是否刪除原檔案
        //引數二:原檔案的路徑(HDFS)
        //引數三:目標地址路徑(Win)
        //引數四:是否開啟本地校驗,true是沒有開啟校驗,最後下載的檔案裡沒有.crc檔案
        fs.copyToLocalFile(false,new Path("/xiyou/huaguoshan/sunwukong.txt"),new Path("C:\\sunwukong1.txt"),false);
    }

3、檔案刪除

    // 刪除
    @Test
    public void testRm() throws IOException {
        //引數一:要刪除的路徑
        //引數二:是否要遞迴刪除
        //fs.delete(new Path("/jdk-8u212-linux-x64.tar.gz"),false);

        //刪除非空目錄
        fs.delete(new Path("/xiyou"),true);
    }

4、檔案更名和移動

    // 檔案的更名和移動
    @Test
    public void testmv() throws IOException {
        //檔名稱修改
        //引數一:原檔案路徑
        //引數二:目標檔案路徑
        //fs.rename(new Path("/input/word.txt"),new Path("/input/SEVENTEEN.txt"));

        //檔案的移動和更名
        fs.rename(new Path("/input/SEVENTEEN.txt"),new Path("/CREW.txt"));

        //目錄的更名
        fs.rename(new Path("/input"),new Path("/result"));
    }

5、檔案詳情檢視

    // 獲取檔案詳細資訊
    @Test
    public void fileDetail() throws IOException {
        // 獲取所有檔案資訊 這是一個迭代器
        RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

        //遍歷檔案
        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));
        }
    }

6、檔案和資料夾的判斷

    // 檔案和資料夾判斷
    @Test
    public void testFile() throws IOException {
        FileStatus[] listStatus = fs.listStatus(new Path("/"));

        for (FileStatus status : listStatus) {
            if (status.isFile()) {
                System.out.println("檔案:" + status.getPath().getName());
            }else {
                System.out.println("目錄:" + status.getPath().getName());
            }
        }
    }

相關文章