1. 程式人生 > >HDFS常用Shell命令和基礎程式設計開發

HDFS常用Shell命令和基礎程式設計開發

HDFS常用Shell命令

Hadoop支援很多Shell命令,其中fs是HDFS最常用的命令,利用fs可以檢視HDFS檔案系統的目錄結構、上傳和下載資料、建立檔案等。

HDFS有三種shell命令方式:

  1. hadoop fs :適用於任何不同的檔案系統,比如本地檔案系統和HDFS檔案系統。
  2. Hadoop dfs:只能適用與HDFS檔案系統。
  3. hdfs dfs:跟hadoop dfs命令作用一樣,也只能適用與HDfS檔案系統。

我這裡的的命令用的都是第三種,hdfs dfs。

對檔案和資料夾的操作:

hdfs dfs -mkdir input
#在HDFS檔案系統中建立一個'input'目錄
hdfs dfs -ls input #列出 input 目錄下的內容 hdfs dfs -put /home/hadoop/myFlie.txt input #將本地的檔案myFile.txt上傳到HDFS檔案系統的input中。 hdfs dfs -get input/myFlie.txt /home/hadoop/下載 #從HDFS檔案系統中下載檔案到本地檔案系統 hdfs dfs -cat input/myFlie.txt #檢視檔案的全部內容 hdfs dfs -cp input/myFile.txt input #在HDFS上覆制檔案 hdfs dfs -mv input/myFile.txt output #在HDFS上移動檔案
hdfs dfs -rm input/myFile.txt #從HDFS刪除檔案 hdfs dfs -du input/myFile.txt #檢視HDFS上某目錄下所有檔案大小,指定檔案後顯示具體檔案大小 hdfs dfs -touchz input/file.txt #建立一個0位元組的空檔案。 hdfs dfs -chmod #改名檔案許可權 hdfs dfs -chown #改變檔案所有者

<center>

圖;操作示例

HDFS dfsadmin管理命令:

  1. hdfs dfsadmin -report

    檢視檔案系統的基本資訊和統計資訊。

  2. hdfs dfsadmin -safemode get/enter

    enter | leave | get | wait:安全模式命令。安全模式是NameNode的一種狀態,在這種狀態下,NameNode不接受對名字空間的更改(只讀);不復制或刪除塊。NameNode在啟動時自動進入安全模式,當配置塊的最小百分數滿足最小副本數的條件時,會自動離開安全模式。enter是進入,leave是離開。

  3. hdfs dfsadmin -refreshNodes

    重新讀取hosts和exclude檔案,使新的節點或需要退出叢集的節點能夠被NameNode重新識別。這個命令在新增節點或登出節點時用到。

  4. hdfs dfsadmin -finalizeUpgrade

    終結HDFS的升級操作。DataNode刪除前一個版本的工作目錄,之後NameNode也這樣做。

  5. hdfs dfsadmin -fupgradeProgress

    status| details | force:請求當前系統的升級狀態 | 升級狀態的細節| 強制升級操作

  6. hdfs dfsadmin -metasave filename

    儲存NameNode的主要資料結構到hadoop.log.dir屬性指定的目錄下的檔案中。

這裡寫圖片描述
圖:操作示例

HDFS API詳解

Hadoop中關於檔案操作類基本上全部是在”org.apache.hadoop.fs”包中,這些API能夠支援的操作包含:開啟檔案,讀寫檔案,刪除檔案等。

Hadoop類庫中最終面向使用者提供的介面類是FileSystem,該類是個抽象類,只能通過來類的get方法得到具體類。get方法存在幾個過載版本,常用的是這個:

static FileSystem get(Configuration conf);

該類封裝了幾乎所有的檔案操作,例如mkdir,delete等。綜上基本上可以得出操作檔案的程式庫框架:

operator()
{
    得到Configuration物件

    得到FileSystem物件

    進行檔案操作
}

為了編寫一個能夠與HDFS互動的Java應用程式,一般需要向Java工程中新增以下JAR包:
(1)”/usr/local/hadoop/share/hadoop/common”目錄下的hadoop-common-2.7.1.jar和haoop-nfs-2.7.1.jar;
(2)/usr/local/hadoop/share/hadoop/common/lib”目錄下的所有JAR包;
(3)“/usr/local/hadoop/share/hadoop/hdfs”目錄下的haoop-hdfs-2.7.1.jar和haoop-hdfs-nfs-2.7.1.jar;
(4)“/usr/local/hadoop/share/hadoop/hdfs/lib”目錄下的所有JAR包。

上傳本地檔案:

通過”FileSystem.copyFromLocalFile(Path src,Patch dst) “可將本地檔案上傳到HDFS的制定位置上,其中src和dst均為檔案的完整路徑。具體程式碼如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;


public class CopyFile {


    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        FileSystem hdfs = FileSystem.get(conf);

        //本地檔案路徑
        Path srcPath = new Path("/home/hadoop/myFile.txt");

        //HDFS路徑
        Path dstPath = new Path("/input/");

        //進行檔案上傳
        hdfs.copyFromLocalFile(srcPath, dstPath);

        //列印hdfs的檔案預設路徑
        System.out.println("複製檔案到: " + conf.get("fs.default.name"));

        FileStatus[] files= hdfs.listStatus(dstPath);

        //列印檔案被複制到的路徑
        for(FileStatus file:files)
            System.out.println(file.getPath());
    }
}

程式執行結果:

複製檔案到: file:///
file:/input

如果遇到因為檔案許可權不夠,程式執行失敗,解決方法如下:

可能出現問題的原因有三種:

  1. hdfs 中的檔案或資料夾 沒有讀取許可權;
  2. hdfs 的配置中未允許拷出文件;
  3. linux 資料夾沒有寫入許可權;

針對上述三個原因,解決方法如下:

  1. 增加hdfs資料夾許可權

    hdfs dfs -chmod 777 /

  2. 修改hdfs配置檔案:

    
    # 在 $HADOOP_HOME/etc/hadoop/目錄中,找到hdfs-site.xml,新增或更改以下屬性:
    
    
    <property>
          <name>dfs.permissions</name>
          <value>false</value>
    </property>
    
    
    # 將true該為false。
    
  3. 增加Linux資料夾許可權:

    sudo chmod 777 /

建立HDFS檔案:

通過”FileSystem.create(Path f)”可在HDFS上建立檔案,其中f為檔案的完整路徑。具體程式碼如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CreatFile {

    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf); 

        //要輸入檔案的字串
        byte[] s = "hello hdfs\n".getBytes();   
        Path dfsPath = new Path("/text.txt");   
        FSDataOutputStream outputStream = hdfs.create(dfsPath);
        //寫入檔案
        outputStream.write(s, 0, s.length);
    }
}

寫入檔案和讀取檔案:

import java.io.BufferedReader;
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 ReadFile {

    public static void main(String[] args) throws Exception{

        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        //要寫入檔案的內容
        byte[] wString = "hello word! \nHello Hadoop!\nHello HDFS!\n".getBytes();

        //要寫入的檔名
        String filename = "file";

        FSDataOutputStream os = hdfs.create(new Path(filename));
        //寫入檔案
        os.write(wString, 0, wString.length);
        os.close();


        FSDataInputStream is = hdfs.open(new Path(filename));
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        //讀取檔案
        String line;
        while((line = br.readLine()) != null)
            System.out.println(line);

        is.close();
        br.close();//
        hdfs.close();   
    }
}

程式執行結果:

hello word! 
Hello Hadoop!
Hello HDFS!

建立HDFS目錄:

通過”FileSystem.mkdirs(Path f)”可在HDFS上建立資料夾,其中f為資料夾的完整路徑。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;


public class CreatDir {

    /**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        Path dfs = new Path("/TextDir");
        hdfs.mkdirs(dfs);

        System.out.println(hdfs.exists(dfs));
    }
}

重新命名HDFS檔案:

通過”FileSystem.rename(Path src,Path dst)”可為指定的HDFS檔案重新命名,其中src和dst均為檔案的完整路徑。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;


public class Rename {

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        Path oldname = new Path("/text.txt");
        Path newname = new Path("/newtext.txt");

        hdfs.rename(oldname, newname);
        System.out.println(hdfs.exists(newname));
    }
}

刪除HDFS上的檔案:

通過”FileSystem.delete(Path f,Boolean recursive)”可刪除指定的HDFS檔案,其中f為需要刪除檔案的完整路徑,recuresive用來確定是否進行遞迴刪除。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class DeleteFile {

    public static void main(String[] args) throws Exception {       
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");      
        FileSystem hdfs = FileSystem.get(conf);

        Path deletePath = new Path("/text4.txt");

        hdfs.delete(deletePath, true);
    }
}

刪除目錄和刪除檔案程式碼一樣,換成路徑就行,如果目錄下有檔案,遞迴刪除。

檢視某個HDFS檔案是否存在:

通過”FileSystem.exists(Path f)”可檢視指定HDFS檔案是否存在,其中f為檔案的完整路徑。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;


public class CheckFile {

    public static void main(String[] args) throws Exception{

        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        Path findpPath = new Path("/input/myFile.txt");

        System.out.println("檔案是否存在:" + hdfs.exists(findpPath));
    }
}
這裡寫圖片描述
圖:HDFS檔案系統結構圖

程式執行結果:

檔案是否存在:true

檢視HDFS檔案的資訊狀態:

通過”FileSystem.getModificationTime()”可檢視指定HDFS檔案的修改時間。具體實現如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.ws.rs.core.NewCookie;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;


public class GetTime {

    public static void main(String[] args) throws Exception{

        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        Path findpPath = new Path("/input/myFile.txt");

        FileStatus fileStatus = hdfs.getFileStatus(findpPath);
        long accessTime = fileStatus.getAccessTime();
        long modeTime = fileStatus.getModificationTime();
        long size = fileStatus.getBlockSize();
        long len = fileStatus.getLen();
        String owner = fileStatus.getOwner();
        Path path = fileStatus.getPath();
        String group = fileStatus.getGroup();

        //將時間戳轉換為格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat();
        String time1 = sdf.format(new Date(accessTime));
        String time2 = sdf.format(new Date(modeTime));


        //獲取檔案的許可權資訊
        System.out.println("檔案的許可權:" + fileStatus.getPermission());  
        System.out.println("檔案建立時間:" + time1);
        System.out.println("檔案修改時間:" + time2);
        System.out.println("HDFS檔案塊大小:" + size);
        System.out.println("檔案大小:" + len);
        System.out.println("檔案所有者:" + owner);
        System.out.println("檔案所在路徑:" + path);
        System.out.println("檔案所屬組:" + group);

    }
}

程式執行結果:

檔案的許可權:rw-r--r--
檔案建立時間:18-6-9 下午1:59
檔案修改時間:18-6-9 下午1:59
HDFS檔案塊大小:134217728
檔案大小:37
檔案所有者:hadoop
檔案所在路徑:hdfs://localhost:9000/input/myFile.txt
檔案所屬組:supergroup

讀取HDFS某個目錄下的所有檔案:

通過”FileStatus.getPath()”可檢視指定HDFS中某個目錄下所有檔案。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class ReadDirFile {

    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        Path dirPath = new Path("/input");

        FileStatus[] stats = hdfs.listStatus(dirPath);

        for(int i = 0; i < stats.length; i++)
            System.out.println(stats[i].getPath().toString());
        hdfs.close();
    }
}
這裡寫圖片描述
圖:input目錄下有兩檔案

程式執行結果如下:

hdfs://localhost:9000/input/myFile.txt
hdfs://localhost:9000/input/text2.txt

查詢某個檔案在HDFS叢集的位置:

通過”FileSystem.getFileBlockLocation(FileStatus file,long start,long len)”可查詢指定檔案在HDFS叢集上的位置,其中file為檔案的完整路徑,start和len來標識查詢檔案的路徑。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.protocol.BlockLocalPathInfo;


public class FileLoc {

    public static void main(String[] args) throws Exception {


        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);
        Path fPath = new Path("/input/myFile.txt");

        FileStatus status = hdfs.getFileStatus(fPath);

        BlockLocation[] blInfo = hdfs.getFileBlockLocations(status, 0, status.getLen());

        for(int i = 0; i < blInfo.length; i++){
            String [] hosts = blInfo[i].getHosts();
            System.out.println("block: " + i + " Location: " + hosts[0]);
        }
    }
}

程式執行結果:

block: 0 Location: ubuntu

獲取HDFS叢集上所有節點名稱資訊:

通過”DatanodeInfo.getHostName()”可獲取HDFS叢集上的所有節點名稱。具體實現如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;


public class GetInfo {

    public static void main(String[] args) throws Exception{

        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://localhost:9000");
        FileSystem hdfs = FileSystem.get(conf);

        DistributedFileSystem dFileSystem = (DistributedFileSystem) hdfs;
        DatanodeInfo[] dInfos = dFileSystem.getDataNodeStats();

        for(int i = 0; i < dInfos.length; i++)
            System.out.println("DataNode_" + i + "_Name:" + dInfos[i].getHostName());
    }
}

程式執行結果:

DataNode_0_Name:ubuntu