Hadoop文件系统访问的两种方式

在这里记录下学习hadoop 的过程,并对重要内容记录下来,以备以后查漏补缺。

要从Hadoop文件系统中读取文件,一般有两种方式:

1.使用java.net.URL对象

package com.ytu.chapter3;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;

public class URLCat {
	static {
		URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
	}
	public static void main(String[] args) {
		InputStream input = null;

		try {
			input = new URL("hdfs://localhost:9000/user/liujiacai/build.xml").openStream();
			IOUtils.copyBytes(input, System.out, 4096, false);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeStream(input);
		}

	}
}

这种方式需要让Java识别Hadoop文件系统的URL方案,就是通过一个FsUrlStreamHandlerFactory实例来调用URL中的setURLStreamHandlerFactory方法。这种方法在一个java虚拟机中只被调用一次,所以一般放在static块中。这个限制意味着如果程序的其他部件设置了一个URLStreamHandlerFactory,我们便无法再从Hadoop中读取数据了。

这需要是我第二种方法。

2.使用FileSystemAPI读取数据

在命令行中,我们可以和使用linux系统命令一样来操作hdfs系统。

hadoop fs -ls /

这个命令可以查看根目录下的文件,如果想要递归查看,参数改为  -lsr 即可

如果想知道更多的帮助可以用以下命令:

hadoop fs -help ls

可以得到ls的用法提示。

这里重点讲解用hadoop api操作hdfs文件系统。

通过调用FileSystem.get(Configuration conf)工厂方法可以得到FileSystem的实例。

Configuration class is a special class for holding key/value configuration parameters.

Configuration对象封装了一个客户端或者服务器的配置,这是用从类路径对去而来的配置文件(如conf/core-site.xml)来设置。

public static FileSystem get(Configuraion conf) throws IOException

这个静态方法返回的是默认文件系统(在conf/core-site.xml中设置,如果没有设置过,则是默认的本地文件系统)。

我们可以这样得到HDFS文件系统:

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

我们可以这样得到本地文件系统

FileSystem local = FileSystem.getLocal(conf);

在hadoop文件api中,我们用Path对象来编码文件名和文件夹名,用FileStatus对象来存储文件与文件夹的元信息(metadata)

import java.io.IOException;

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

public class PutMerge {

	public static void main(String[] args) throws IOException {
		Configuration conf = new Configuration();
		FileSystem hdfs = FileSystem.get(conf);
		FileSystem local = FileSystem.getLocal(conf);

		Path inputDir = new Path(args[0]);
		Path outputDir = new Path(args[1]);

		FileStatus[] inputFiles = local.listStatus(inputDir);

		//FSDataOutputStream是Java标准库java.io.DataOutputSteam的子类,同时增加了随机访问的功能
		FSDataOutputStream out = hdfs.create(outputDir);

		for (int i = 0; i < inputFiles.length; i++) {
			System.out.println(inputFiles[i].getPath().getName());
			FSDataInputStream in = local.open(inputFiles[i].getPath());//默认4K为缓冲区大小
			byte[] buffer = new byte[256];
			int bytesRead = 0;
			while((bytesRead = in.read(buffer))>0) {
				out.write(buffer,0,bytesRead);
			}
			in.close();
		}
		out.close();
	}

}

上面这个完整的程序完成的功能是:把本地的一个文件夹中的文件再上传到hdfs文件系统时将它们合并。

除此之外FileSystem类也有诸如delete(),exists(),mkdirs(),rename()等方法。

FSDataInputStream不是标准的java.io类,这个类是java.io.DataInputStream的一个子类,支持随机访问,这样就可以从流的任意位置读取数据了。

public class FSDataInputStream extends DataInputStream
    implements Seekable, PositionedReadable, Closeable 

上面是它的签名,Seekable接口允许在文件中定位,并提供一个查询方式,用于查询当前位置相对于文件开始位置的偏移量。

public interface Seekable {
  /**
   * Seek to the given offset from the start of the file.
   * The next read() will be from that location.  Can't
   * seek past the end of the file.
   */
  void seek(long pos) throws IOException;

  /**
   * Return the current offset from the start of the file
   */
  long getPos() throws IOException;

  /**
   * Seeks a different copy of the data.  Returns true if
   * found a new source, false otherwise.
   */
  boolean seekToNewSource(long targetPos) throws IOException;
}

调用seek方法来定位大于文件长度的位置会导致IOException异常。与java.io.InputStream中的skip()方法不同,seek()并没有指出数据流当前位置之后的一点,他可以转移到文件中任何一个位置。

应用程序员并不常用seekToNewSource方法。此方法一般倾向于切换到数据的另一个副本并在新的副本中寻找targetPos指定的位置。HDFS内部就采用这种方式在数据节点故障时为客户端提供可靠的数据流。

FsDataInputStream也实现了PositionedReadable接口

public interface PositionedReadable {
  /**
   * Read upto the specified number of bytes, from a given
   * position within a file, and return the number of bytes read. This does not
   * change the current offset of a file, and is thread-safe.
   */
  public int read(long position, byte[] buffer, int offset, int length)
    throws IOException;

  /**
   * Read the specified number of bytes, from a given
   * position within a file. This does not
   * change the current offset of a file, and is thread-safe.
   */
  public void readFully(long position, byte[] buffer, int offset, int length)
    throws IOException;

  /**
   * Read number of bytes equalt to the length of the buffer, from a given
   * position within a file. This does not
   * change the current offset of a file, and is thread-safe.
   */
  public void readFully(long position, byte[] buffer) throws IOException;
}

这个接口内的方法都会保留文件当前位置并且是线程安全的,因此他们提供了在读取文件的主要部分时访问其他部分的便利方法。

最后务必记住:seek方法是一个相对高开销的操作,需要慎重使用。

时间: 2025-01-20 13:45:19

Hadoop文件系统访问的两种方式的相关文章

javascript面向对象之访问对象属性的两种方式分析_javascript技巧

本文实例分析了javascript面向对象之访问对象属性的两种方式.分享给大家供大家参考.具体如下: javascript面向对象的访问对象属性的两种方式.如下代码所示: 复制代码 代码如下: <script language="javascript" type="text/javascript"> function Person(){}; var p1 = new Person(); p1.name="王美人"; document.

FTP文件传输协议两种方式的工作原理

FTP是一种文件传输协议,它支持两种模式,一种方式叫做Standard (也就是 Active,主动方式),一种是 Passive (也就是PASV,被动方式). Standard模式 FTP的客户端发送 PORT 命令到FTP server.Passive模式FTP的客户端发送 PASV命令到 FTP Server. 下面介绍一个这两种方式的工作原理: Standard模式 FTP 客户端首先和FTP Server的TCP 21端口建立连接,通过这个通道发送命令,客户端需要接收数据的时候在这个

oracle中dblink创建的两种方式

当用户要跨本地数据库,访问另外一个数据库表中的数据时,本地数据库中必须创建了远程数据库的dblink,通过dblink本地数据库可以像访问本地数据库一样访问远程数据库表中的数据.下面讲介绍如何在本地数据库中创建dblink. 创建dblink一般有两种方式,不过在创建dblink之前用户必须有创建dblink的权限.想知道有关dblink的权限,以sys用户登录到本地数据库: select * from user_sys_privs t where t.privilege like upper(

Flume直接到SparkStreaming的两种方式

Flume直接到SparkStreaming的两种方式,一般是flume->kafka->SparkStreaming,如果非要从Flume直接将数据输送到SparkStreaming里面有两种方式,如下: 第一种:Push推送的方式 程序如下: package cn.lijie import org.apache.log4j.Level import org.apache.spark.streaming.flume.FlumeUtils import org.apache.spark.str

SqlServer2008 数据库同步的两种方式(Sql JOB)

原文:SqlServer2008 数据库同步的两种方式(Sql JOB)   数据库同步是一种比较常用的功能.以下结合我自己的体会整理的,如果有理解不完全或者有误的地方望大牛不理赐教.下面介绍的就是数据库同步的两种方式: 1.SQL JOB的方式  sql Job的方式同步数据库就是通过SQL语句,将一个数据源中的数据同步到目标数据库中.特点是它可以灵活的通过SQL的方式进行数据库之间的同步操作.可以在制定的时间时间作为任务计划自动执行.缺点是需要写SQL来进行操作.既然是数据库之间的同步就涉及

不停止MySQL服务增加从库的两种方式

 现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库.前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作.  一般在线增加从库有两种方式,一种是通过mysqldump备份主库,恢复到从库,mysqldump是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长.另一种是通过xtrabackup工具备份主库,恢复到从库,xtrabackup是物理备份,备份速度快,不锁表.为什么不锁表?因为自身会监控主

免遭勒索软件侵害必备技能之:两种方式解除恶意密码加密

系统被黑只是时间问题?即使如此还是有办法来延缓勒索软件的攻击.我们在第一部分<免遭勒索软件侵害必备技能之:换位思考>中介绍,对于盛行的勒索软件,你需要换位思考:如果病毒感染了用户的计算机,它会在什么账号下发作?是用户的域帐户?本地管理员的帐户,还是系统帐户和网络帐户?专家TREVOR POTT给出了自己的答案. 本文为第二部分,更多专家将介绍防止Windows用户数据被恶意加密的两种方式以及企业级PowerShell环境对勒索软件产生的影响. 勒索软件体现出恶意软件对企业级IT领域不断变化的威

不停止 MySQL 服务增加从库的两种方式

现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库.前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作.  一般在线增加从库有两种方式,一种是通过mysqldump备份主库,恢复到从库,mysqldump是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长.另一种是通过xtrabackup工具备份主库,恢复到从库,xtrabackup是物理备份,备份速度快,不锁表.为什么不锁表?因为自身会监控主库

二维数组的认识及其表示元素的两种方式

/* ============================================================================ Name : TeatArr.c Author : lf Version : Copyright : Your copyright notice Description : 二维数组的认识以及其表示元素的两种方式 备注说明 1 要理解二维数组的存储方式. 2 实际上利用a[i][j]的方式并不"正统",但这靠近我们的 常识一些,