在之前我們已經(jīng)介紹了如何在Linux上進(jìn)行HDFS偽分布式環(huán)境的搭建,也介紹了hdfs中一些常用的命令。但是要如何在代碼層面進(jìn)行操作呢?這是本節(jié)將要介紹的內(nèi)容:
目前創(chuàng)新互聯(lián)已為成百上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁(yè)空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、聞喜網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
1.首先使用IDEA創(chuàng)建一個(gè)maven工程:
maven默認(rèn)是不支持cdh的倉(cāng)庫(kù)的,需要在pom.xml中配置cdh的倉(cāng)庫(kù),如下:
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>
注意:如果你maven的settings.xml文件中,將mirrorOf
的值配置成了*
的話,那么就需要將其修改為*,!cloudera
或central
,因?yàn)?code>*表示覆蓋所有倉(cāng)庫(kù)地址會(huì)導(dǎo)致maven無(wú)法從cloudera的倉(cāng)庫(kù)下載依賴包,而*,!cloudera
表示不覆蓋id為cloudera的倉(cāng)庫(kù),關(guān)于這個(gè)問(wèn)題可以自行了解一下。具體配置如下示例:
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>*,!cloudera</mirrorOf>
</mirror>
最后添加相關(guān)的依賴項(xiàng):
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hadoop.version>2.6.0-cdh6.7.0</hadoop.version>
</properties>
<dependencies>
<!-- hadoop依賴 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
<!-- 單元測(cè)試依賴 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
搭建完工程環(huán)境后,我們就可以調(diào)用Hadoop的API來(lái)操作HDFS文件系統(tǒng)了,下面我們來(lái)寫一個(gè)測(cè)試用例,在HDFS文件系統(tǒng)上創(chuàng)建一個(gè)目錄:
package org.zero01.hadoop.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.net.URI;
/**
* @program: hadoop-train
* @description: Hadoop HDFS Java API 操作
* @author: 01
* @create: 2018-03-25 13:59
**/
public class HDFSAPP {
// HDFS文件系統(tǒng)服務(wù)器的地址以及端口
public static final String HDFS_PATH = "hdfs://192.168.77.130:8020";
// HDFS文件系統(tǒng)的操作對(duì)象
FileSystem fileSystem = null;
// 配置對(duì)象
Configuration configuration = null;
/**
* 創(chuàng)建HDFS目錄
*/
@Test
public void mkdir()throws Exception{
// 需要傳遞一個(gè)Path對(duì)象
fileSystem.mkdirs(new Path("/hdfsapi/test"));
}
// 準(zhǔn)備資源
@Before
public void setUp() throws Exception {
configuration = new Configuration();
// 第一參數(shù)是服務(wù)器的URI,第二個(gè)參數(shù)是配置對(duì)象,第三個(gè)參數(shù)是文件系統(tǒng)的用戶名
fileSystem = FileSystem.get(new URI(HDFS_PATH), configuration, "root");
System.out.println("HDFSAPP.setUp");
}
// 釋放資源
@After
public void tearDown() throws Exception {
configuration = null;
fileSystem = null;
System.out.println("HDFSAPP.tearDown");
}
}
運(yùn)行結(jié)果:
可以看到是運(yùn)行成功的,然后到服務(wù)器上,查看文件是否多了我們創(chuàng)建的目錄:
[root@localhost ~]# hdfs dfs -ls /
Found 3 items
-rw-r--r-- 1 root supergroup 311585484 2018-03-24 23:15 /hadoop-2.6.0-cdh6.7.0.tar.gz
drwxr-xr-x - root supergroup 0 2018-03-25 22:17 /hdfsapi
-rw-r--r-- 1 root supergroup 49 2018-03-24 23:10 /hello.txt
[root@localhost ~]# hdfs dfs -ls /hdfsapi
Found 1 items
drwxr-xr-x - root supergroup 0 2018-03-25 22:17 /hdfsapi/test
[root@localhost ~]#
如上,代表我們的目錄創(chuàng)建成功了。
我們?cè)賮?lái)增加一個(gè)方法,測(cè)試創(chuàng)建文件,并寫入一些內(nèi)容到文件中:
/**
* 創(chuàng)建文件
*/
@Test
public void create() throws Exception {
// 創(chuàng)建文件
FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test/a.txt"));
// 寫入一些內(nèi)容到文件中
outputStream.write("hello hadoop".getBytes());
outputStream.flush();
outputStream.close();
}
執(zhí)行成功后,同樣的到服務(wù)器上,查看是否有我們創(chuàng)建的文件,并且文件的內(nèi)容是否是我們寫入的內(nèi)容:
[root@localhost ~]# hdfs dfs -ls /hdfsapi/test
Found 1 items
-rw-r--r-- 3 root supergroup 12 2018-03-25 22:25 /hdfsapi/test/a.txt
[root@localhost ~]# hdfs dfs -text /hdfsapi/test/a.txt
hello hadoop
[root@localhost ~]#
每次操作完都得去服務(wù)器上查看,很麻煩,其實(shí)我們也可以直接在代碼中讀取文件系統(tǒng)中某個(gè)文件的內(nèi)容,如下示例:
/**
* 查看HDFS里某個(gè)文件的內(nèi)容
*/
@Test
public void cat() throws Exception {
// 讀取文件
FSDataInputStream in = fileSystem.open(new Path("/hdfsapi/test/a.txt"));
// 將文件內(nèi)容輸出到控制臺(tái)上,第三個(gè)參數(shù)表示輸出多少字節(jié)的內(nèi)容
IOUtils.copyBytes(in, System.out, 1024);
in.close();
}
現(xiàn)在創(chuàng)建目錄、文件以及讀取文件內(nèi)容都知道如何操作了,或許我們還需要知道如何重命名文件,如下示例:
/**
* 重命名文件
*/
@Test
public void rename() throws Exception {
Path oldPath = new Path("/hdfsapi/test/a.txt");
Path newPath = new Path("/hdfsapi/test/b.txt");
// 第一個(gè)參數(shù)是原文件的名稱,第二個(gè)則是新的名稱
fileSystem.rename(oldPath, newPath);
}
增、查、改我們都已經(jīng)知道如何操作了,就差最后一個(gè)刪除的操作了,如下示例:
/**
* 刪除文件
* @throws Exception
*/
@Test
public void delete()throws Exception{
// 第二個(gè)參數(shù)指定是否要遞歸刪除,false=否,true=是
fileSystem.delete(new Path("/hdfsapi/test/MySQL_cluster.iso"), false);
}
對(duì)文件的增、刪、查、改都介紹完了,下面我們來(lái)看看如何上傳本地文件到HDFS文件系統(tǒng)中,我這里有一個(gè)local.txt文件,文件內(nèi)容如下:
This is a local file
編寫測(cè)試代碼如下:
/**
* 上傳本地文件到HDFS
*/
@Test
public void copyFromLocalFile() throws Exception {
Path localPath = new Path("E:/local.txt");
Path hdfsPath = new Path("/hdfsapi/test/");
// 第一個(gè)參數(shù)是本地文件的路徑,第二個(gè)則是HDFS的路徑
fileSystem.copyFromLocalFile(localPath, hdfsPath);
}
執(zhí)行以上的方法成功后,我們到HDFS上,看看是否拷貝成功:
[root@localhost ~]# hdfs dfs -ls /hdfsapi/test/
Found 2 items
-rw-r--r-- 3 root supergroup 12 2018-03-25 22:33 /hdfsapi/test/b.txt
-rw-r--r-- 3 root supergroup 20 2018-03-25 22:45 /hdfsapi/test/local.txt
[root@localhost ~]# hdfs dfs -text /hdfsapi/test/local.txt
This is a local file
[root@localhost ~]#
以上演示了上傳一個(gè)小的文件,但是如果我需要上傳一個(gè)比較大的文件,并且還希望有個(gè)進(jìn)度條的話,就得使用以下這個(gè)種方式了:
/**
* 上傳大體積的本地文件到HDFS,并顯示進(jìn)度條
*/
@Test
public void copyFromLocalFileWithProgress() throws Exception {
InputStream in = new BufferedInputStream(new FileInputStream(new File("E:/Linux Install/mysql_cluster.iso")));
FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test/mysql_cluster.iso"), new Progressable() {
public void progress() {
// 進(jìn)度條的輸出
System.out.print(".");
}
});
IOUtils.copyBytes(in, outputStream, 4096);
in.close();
outputStream.close();
}
同樣的,執(zhí)行以上的方法成功后,我們到HDFS上,看看是否上傳成功:
[root@localhost ~]# hdfs dfs -ls -h /hdfsapi/test/
Found 3 items
-rw-r--r-- 3 root supergroup 12 2018-03-25 22:33 /hdfsapi/test/b.txt
-rw-r--r-- 3 root supergroup 20 2018-03-25 22:45 /hdfsapi/test/local.txt
-rw-r--r-- 3 root supergroup 812.8 M 2018-03-25 23:01 /hdfsapi/test/mysql_cluster.iso
[root@localhost ~]#
既然有上傳文件自然就有下載文件,而且上傳文件的方式有兩種。所以下載文件的方式也有兩種,如下示例:
/**
* 下載HDFS文件1
*
*/
@Test
public void copyToLocalFile1() throws Exception {
Path localPath = new Path("E:/b.txt");
Path hdfsPath = new Path("/hdfsapi/test/b.txt");
fileSystem.copyToLocalFile(hdfsPath, localPath);
}
/**
* 下載HDFS文件2
*
*/
@Test
public void copyToLocalFile2() throws Exception {
FSDataInputStream in = fileSystem.open(new Path("/hdfsapi/test/b.txt"));
OutputStream outputStream = new FileOutputStream(new File("E:/b.txt"));
IOUtils.copyBytes(in, outputStream, 1024);
in.close();
outputStream.close();
}
下面我們來(lái)演示一下如何列出某個(gè)目錄下的所有文件,示例:
/**
* 查看某個(gè)目錄下所有的文件
*
* @throws Exception
*/
@Test
public void listFiles() throws Exception {
FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/hdfsapi/test/"));
for (FileStatus fileStatus : fileStatuses) {
System.out.println("這是一個(gè):" + (fileStatus.isDirectory() ? "文件夾" : "文件"));
System.out.println("副本系數(shù):" + fileStatus.getReplication());
System.out.println("大?。? + fileStatus.getLen());
System.out.println("路徑:" + fileStatus.getPath() + "\n");
}
}
控制臺(tái)打印結(jié)果如下:
這是一個(gè):文件
副本系數(shù):3
大小:12
路徑:hdfs://192.168.77.130:8020/hdfsapi/test/b.txt
這是一個(gè):文件
副本系數(shù):3
大?。?0
路徑:hdfs://192.168.77.130:8020/hdfsapi/test/local.txt
這是一個(gè):文件
副本系數(shù):3
大?。?52279296
路徑:hdfs://192.168.77.130:8020/hdfsapi/test/mysql_cluster.iso
注意,從控制臺(tái)打印結(jié)果中,我們可以看到一個(gè)問(wèn)題:我們之前已經(jīng)在hdfs-site.xml中設(shè)置了副本系數(shù)為1,為什么此時(shí)查詢文件看到的系數(shù)是3呢?
其實(shí)這是因?yàn)檫@幾個(gè)文件都是我們?cè)诒镜赝ㄟ^(guò)Java API上傳上去的,在本地我們并沒(méi)有設(shè)置副本系數(shù),所以這時(shí)就會(huì)使用Hadoop的默認(rèn)副本系數(shù):3。
如果我們是在服務(wù)器上,通過(guò)hdfs命令put上去的,那么才會(huì)采用我們?cè)谂渲梦募性O(shè)置的副本系數(shù)。不信的話,可以在代碼中將路徑修改為根目錄,這時(shí)控制臺(tái)輸出如下:
這是一個(gè):文件
副本系數(shù):1
大小:311585484
路徑:hdfs://192.168.77.130:8020/hadoop-2.6.0-cdh6.7.0.tar.gz
這是一個(gè):文件夾
副本系數(shù):0
大?。?
路徑:hdfs://192.168.77.130:8020/hdfsapi
這是一個(gè):文件
副本系數(shù):1
大?。?9
路徑:hdfs://192.168.77.130:8020/hello.txt
根目錄下的文件都是我們之前通過(guò)hdfs命令put上去,所以這些文件的副本系數(shù)才是我們?cè)谂渲梦募性O(shè)置的副本系數(shù)。
關(guān)于HDFS寫數(shù)據(jù)流程,我在網(wǎng)絡(luò)上找到一篇描述非常簡(jiǎn)潔易懂的漫畫(huà)形式講解HDFS的原理,作者不詳。比一般PPT要通俗易懂很多,是難得的學(xué)習(xí)資料,特此摘錄到本文中。
1、三個(gè)部分: 客戶端、NameNode(可理解為主控和文件索引類似linux的inode)、DataNode(存放實(shí)際數(shù)據(jù)的存server)
2、HDFS寫數(shù)據(jù)過(guò)程:
3、讀取數(shù)據(jù)過(guò)程
4、容錯(cuò):第一部分:故障類型及其檢測(cè)方法(nodeserver 故障,和網(wǎng)絡(luò)故障,和臟數(shù)據(jù)問(wèn)題)
5、容錯(cuò)第二部分:讀寫容錯(cuò)
6、容錯(cuò)第三部分:dataNode 失效
7、備份規(guī)則
8、結(jié)束語(yǔ)
關(guān)于這個(gè)漫畫(huà)還有一個(gè)中文版的,地址如下:
https://www.cnblogs.com/raphael5200/p/5497218.html
HDFS優(yōu)點(diǎn):
HDFS缺點(diǎn):
本文題目:Java操作HDFS開(kāi)發(fā)環(huán)境搭建以及HDFS的讀寫流程
當(dāng)前地址:http://jinyejixie.com/article42/jdoehc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開(kāi)發(fā)、外貿(mào)網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化、網(wǎng)站制作、手機(jī)網(wǎng)站建設(shè)、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)