經過本章節您能夠學習到java
一、將hadoop2.7.2.tar.gz解壓到指定目錄,例如linux
D:/software/hadoop-2.7.2
hadoop2.7.2.tar.gz就是咱們一開始在linux解壓的編譯包。shell
二、添加win10所需的組件到bin目錄(D:/software/hadoop-2.7.2/bin):將hadoopBin.rar解壓,並將裏面的7個文件複製到D:/software/hadoop-2.7.2/bin目錄。apache
本系列相關的教程都會在章節
【hadoop】1.Hadoop簡介
中提供的百度外鏈下載到。windows
個人是win10環境,因此須要添加以上的組件。maven
若是你的版本不一致,能夠從相關網站下載到編譯包,至少目前hadoop已經3.x了。ide
一、添加HADOOP_HOME變量,值爲D:/software/hadoop-2.7.2/;oop
二、編輯PATH變量,添加新值%HADOOP_HOME%\bin
學習
三、進入windows命令行界面,檢測是否成功測試
四、關聯集羣hosts主機名,修改windows的主機文件
C:\Windows\System32\drivers\etc 添加下面3臺主機映射
五、建立目錄D:\hadoop
,並在內部建立一個test.txt文件,隨便寫入一些內容。接下來咱們的測試就是將這個文件上傳到HDFS集羣。
接下來須要本身建立的測試文件就本身建立測試,這裏不做過多說明了。
一、使用idea建立一個maven項目
二、配置pom文件,信息以下
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhaoyi</groupId> <artifactId>firsthadoop</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <hadoop.version>2.7.3</hadoop.version> </properties> <dependencies> <!-- 引入hadoop相關依賴 --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>${hadoop.version}</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>${hadoop.version}</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>${hadoop.version}</version> </dependency> </dependencies> </project>
三、建立類com.zhaoyi.hdfs.HDFSClient
package com.zhaoyi; import com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.junit.Test; import java.net.URI; public class HDFSClient { private final static String HADOOP_USER = "root"; private final static String HDFS_URL = "hdfs://h133:8020"; public static void main(String[] args) throws Exception { // 一、獲取配置實體 final Configuration configuration = new Configuration(); // 二、獲取文件系統 FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration,HADOOP_USER); // 三、拷貝本地數據到集羣 fileSystem.copyFromLocalFile(new Path("D:/hadoop/test.txt"),new Path("/user/zhaoyi/input")); // 四、關閉文件系統 fileSystem.close(); } }
運行該類,就能夠發現咱們建立的文件上傳到了/user/zhaoyi/input
下。接下來咱們就在該類的基礎上進行其餘的測試。
FileSystem.get共有3個重載方法,前兩個方法提取的默認認證用戶名都爲當前用戶的帳戶名,所以,若是您不指定用戶名,會使用你的當前windows帳戶去認證,顯然是沒辦法經過的。不過,若是你的HADOOP_USER和WINDOWS_USER一致的話,這裏不會有什麼問題。推薦使用get的第三個重載方法獲取文件系統。
@Test // 獲取文件系統 public void getFileSystem() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration,HADOOP_USER); // print fs info System.out.println(fileSystem); }
輸出
DFS[DFSClient[clientName=DFSClient_NONMAPREDUCE_-1963602416_1, ugi=root (auth:SIMPLE)]]
編寫測試用例
@Test public void putFileToHDFS() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); // set destination path String destinationPath = "/user/yuanyong"; // uploadFile fileSystem.copyFromLocalFile(true, new Path("D:/hadoop/前塵如夢.txt"),new Path(destinationPath) ); // close fs fileSystem.close(); }
咱們來查看copyFromLocalFile的源碼信息,第一個參數的最終執行:
return deleteSource ? srcFS.delete(src, true) : true;
該參數設置爲true,則表明上傳完成以後會將源文件給刪除,是否是以爲很像move操做。若是您不想讓他刪除,能夠省略此參數,或者設置爲false便可。
@Test public void getFileFromHDFS() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); // set download path. String downloadPath = "D:/"; // fileSystem.copyToLocalFile(new Path("/user/new.file"),new Path(downloadPath)); fileSystem.copyToLocalFile(false,new Path("/user/new.file"),new Path(downloadPath),false); fileSystem.close(); }
一樣,fileSystem.copyToLocalFile也有3個重載方法,其中第三個重載方法的第一個參數指定是否刪除源文件,最後一個參數指定是否執行本地的文件系統校檢(默認false),false則會在本地生成一個名爲.filename.crc的校檢文件,設置爲true則不生成
關於文件校檢:不指定本地校檢時,會透明的建立一個.filename.crc的文件。校驗文件大小的字節數由io.bytes.per.checksum屬性設置,默認是512bytes,即每512字節就生成一個CRC-32校驗和。
@Test public void makeDirInHDFS() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); fileSystem.mkdirs(new Path("/user/areya/my/best/love")); System.out.println("create dir success."); fileSystem.close(); }
建立目錄默認就是遞歸方式。
fileSystem.mkdirs有兩個重載方法,另一個
public boolean mkdirs(Path var1, FsPermission var2)
具體用到再說明。
@Test public void deleteInHDFS() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); fileSystem.delete(new Path("/user/areya"),true); System.out.println("delete dir success."); fileSystem.close(); }
fileSystem.delete也可只指定一個參數,不過該方法會在從此的版本刪除,不推薦使用。
@Test public void renameInHDFS() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); fileSystem.rename(new Path("/user/yuanyong"),new Path("/user/hongqun")); System.out.println("rename dir success."); fileSystem.close(); }
接下來咱們將當前測試在HDFS上的全部文件相關信息都打印一遍。
@Test public void getFileInfoInHDFS() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); // get all file. RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true); while (listFiles.hasNext()){ System.out.println("------------------"); LocatedFileStatus fileStatus = listFiles.next(); System.out.println("path: " + fileStatus.getPath()); System.out.println("group: " + fileStatus.getGroup()); System.out.println("owner: " + fileStatus.getOwner()); System.out.println("access time: " + fileStatus.getAccessTime()); System.out.println("block size: " + fileStatus.getBlockSize()); System.out.println("length: " + fileStatus.getLen()); System.out.println("modify time: " + fileStatus.getModificationTime()); System.out.println("modify time: " + fileStatus.getModificationTime()); System.out.println("permission: " + fileStatus.getPermission()); System.out.println("replicate: " + fileStatus.getReplication()); // System.out.println("symlink: " + fileStatus.getSymlink()); System.out.println("This file blocks info:"); BlockLocation[] blockLocations = fileStatus.getBlockLocations(); for (BlockLocation blockLocation:blockLocations) { System.out.println("block length:" + blockLocation.getLength()); System.out.println("block offsets:" + blockLocation.getOffset()); System.out.println("block hosts:"); for (String host : blockLocation.getHosts()) { System.out.println(host); } } } System.out.println("-------------"); System.out.println("print end."); }
輸出結果:
path: hdfs://h133:8020/user/hongqun/前塵如夢.txt group: supergroup owner: root access time: 1546474991076 block size: 134217728 length: 20 modify time: 1546474991244 modify time: 1546474991244 permission: rw-r--r-- replicate: 3 This file blocks info: block length:20 block offsets:0 block hosts: h133 h135 h134 ------------------ path: hdfs://h133:8020/user/hongqun/test/new.file group: supergroup owner: root access time: 1546465187927 block size: 134217728 length: 21 modify time: 1546465174342 modify time: 1546465174342 permission: rw-r--r-- replicate: 3 This file blocks info: block length:21 block offsets:0 block hosts: h135 h134 h133 ------------------ path: hdfs://h133:8020/user/new.file group: supergroup owner: root access time: 1546477521786 block size: 134217728 length: 21 modify time: 1546465709803 modify time: 1546465709803 permission: rw-r--r-- replicate: 3 This file blocks info: block length:21 block offsets:0 block hosts: h133 h134 h135
從輸出結果咱們能夠了解到listFiles方法只會列出全部的文件(而非文件夾)信息。
前面咱們經過listFiles獲取了文件的信息,接下來咱們獲取某個路徑下文件的信息,並輸出其中的文件和文件夾類型文件。
@Test public void getAllFileInfoInHDFS() throws Exception { Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); // get dir "/user"'s file. FileStatus[] listFiles = fileSystem.listStatus(new Path("/user")); for (FileStatus fileStatus:listFiles) { if(fileStatus.isDirectory()){ System.out.println("dir:" + fileStatus.getPath().getName()); }else if(fileStatus.isFile()){ System.out.println("file:" + fileStatus.getPath().getName()); }else if(fileStatus.isEncrypted()){ System.out.println("cry:" + fileStatus.getPath().getName()); }else if(fileStatus.isSymlink()){ System.out.println("symlink:" + fileStatus.getPath().getName()); } } System.out.println("-------------"); System.out.println("print end."); } System.out.println("print end."); }
輸出以下:
dir:hongqun file:new.file dir:zhaoyi ------------- print end.
HDFS中可能存在4種類型的文件。
總結一下咱們以上的操做共性:
// 1. 建立配置對象 Configuration configuration = new Configuration(); // 2. 建立文件系統操做對象:設置文件系統URI、配置信息以及HDFS用戶名 FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL), configuration, HADOOP_USER); // 3. 執行操做 fileSystem.xxxx(parameter);
接下來咱們經過IO流方式完成文件的一些常規上傳下載操做。從新建立一個客戶端類。
package com.zhaoyi; 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; import org.apache.hadoop.io.IOUtils; import org.junit.Test; import java.io.FileInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; public class HDFSIOClient { private final static String HADOOP_USER = "root"; private final static String HDFS_URL = "hdfs://h133:8020"; @Test public void uploadFile() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration, HADOOP_USER); // 1. 獲取輸入流 FileInputStream fis = new FileInputStream(new File("D:/hadoop/天淨沙.txt")); // 2. 獲取輸出流 FSDataOutputStream fos = fileSystem.create(new Path("/user/天淨沙.txt")); // 3. 流對接 & 關閉流 try { IOUtils.copyBytes(fis, fos,configuration); System.out.println("upload file success."); } catch (IOException e) { e.printStackTrace(); }finally { fis.close(); fos.close(); fileSystem.close(); } } }
輸出與輸入的參考系是相對於當前內存系統(也能夠理解爲咱們的客戶端)而言的。本地文件系統屬於輸入流,上傳的目的地HDFS文件系統則屬於輸出流。
@Test public void downloadFile() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration, HADOOP_USER); // 1. 獲取輸入流 FSDataInputStream fis = fileSystem.open(new Path("/user/奧丁的子女.txt")); // 2. 獲取輸出流 FileOutputStream fos = new FileOutputStream(new File("D:/hadoop/奧丁的子女.txt")); // 3. 流對接&關閉流 try { IOUtils.copyBytes(fis, fos,configuration); System.out.println("download file success."); } catch (IOException e) { e.printStackTrace(); }finally { fis.close(); fos.close(); fileSystem.close(); } }
從這裏咱們要明白:相對於本地客戶端來講,本地文件系統在下載模式下屬於輸出的對象,所以使用輸出流對應;HDFS文件系統屬於輸入的對象,所以使用輸入流,FileSystem的create建立輸出流,open方法建立輸入流。
還記得咱們以前的很大的hadoop安裝文件夾嗎,接下來咱們來定位方式下載該文件。您也能夠從新上傳一次:
[root@h133 ~]# hadoop fs -put /opt/software/hadoop-2.7.2.tar.gz /user/ [root@h133 ~]# hadoop fs -ls /user/ Found 6 items -rw-r--r-- 3 root supergroup 212046774 2019-01-03 11:06 /user/hadoop-2.7.2.tar.gz drwxr-xr-x - root supergroup 0 2019-01-03 08:23 /user/hongqun -rw-r--r-- 3 root supergroup 21 2019-01-03 05:48 /user/new.file drwxr-xr-x - root supergroup 0 2019-01-03 06:11 /user/zhaoyi -rw-r--r-- 3 root supergroup 28 2019-01-03 10:39 /user/天淨沙.txt -rw-r--r-- 3 root supergroup 167 2019-01-03 10:50 /user/奧丁的子女.txt
接下來咱們下載hadoop-2.7.2.tar.gz,分紅兩部分:第一次下載128M,剩餘的放到第二次進行下載。
// 進行第一次下載 @Test public void downloadFileBySeek1() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration, HADOOP_USER); // part 1. 128M // 1. 獲取輸入流 FSDataInputStream inputStream = fileSystem.open(new Path("/user/hadoop-2.7.2.tar.gz")); // 2. 獲取輸出流 FileOutputStream outputStream = new FileOutputStream(new File("D:/hadoop/hadoop-2.7.2.tar.gz.part1")); // 3. 流對接(第一部分只需讀取128M便可) byte[] buff = new byte[1024]; try { for (int i = 0; i < 1024 * 128; i++) { inputStream.read(buff); outputStream.write(buff); } } finally { IOUtils.closeStream(inputStream); IOUtils.closeStream(outputStream); IOUtils.closeStream(fileSystem); } } // 進行第一次下載 @Test public void downloadFileBySeek1() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration, HADOOP_USER); // part 1. 128M // 1. 獲取輸入流 FSDataInputStream inputStream = fileSystem.open(new Path("/user/hadoop-2.7.2.tar.gz")); // 2. 獲取輸出流 FileOutputStream outputStream = new FileOutputStream(new File("D:/hadoop/hadoop-2.7.2.tar.gz.part1")); // 3. 流對接(第一部分只需讀取128M便可) byte[] buff = new byte[1024]; try { for (int i = 0; i < 1024 * 128; i++) { inputStream.read(buff); outputStream.write(buff); } } finally { IOUtils.closeStream(inputStream); IOUtils.closeStream(outputStream); IOUtils.closeStream(fileSystem); } } // 第二次尋址下載 @Test public void downloadFileBySeek2() throws Exception{ Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI(HDFS_URL),configuration, HADOOP_USER); // part 1. 128M // 1. 獲取輸入流 FSDataInputStream inputStream = fileSystem.open(new Path("/user/hadoop-2.7.2.tar.gz")); // 2. 獲取輸出流 FileOutputStream outputStream = new FileOutputStream(new File("D:/hadoop/hadoop-2.7.2.tar.gz.part2")); // 3. 指向第二塊數據地址 inputStream.seek(1024 * 1024 * 128); try { IOUtils.copyBytes(inputStream,outputStream,configuration); } finally { IOUtils.closeStream(inputStream); IOUtils.closeStream(outputStream); IOUtils.closeStream(fileSystem); } }
分別運行兩個測試方法以後,在目錄D:/hadoop/下就會生成兩個tar.gz.part1和part2的分塊文件。接下來運行windows命令行執行追加劇定向操做,將兩個文件合併爲1個。
type hadoop-2.7.2.tar.gz* > hadoop-2.7.2.tar.gz
便可合併咱們最初的hadoop壓縮包文件,能夠經過解壓縮或者md5計算驗證是否一致。
本系列的文章參考資料來源有3個地方: