RawLocalFileSystem是hadoop中实现的本地文件系统,在该类中与文件元数据和目录相关的操作,都是通过适配方式适配到java.io.File的对应API来完成的,适配过程简单,代码清晰。

1.文件元数据和目录相关的操作分析

下面主要以mkDirs()方法为例来窥探该类的实现和一些独到之处。

/****************************************************************
* Implement the FileSystem API for the raw local filesystem.
*
* 本地文件系统实现,文件元数据和目录相关的操作都是通过适配到java.io.File的对应API完成的。
*****************************************************************/
public class RawLocalFileSystem extends FileSystem {
  static final URI NAME = URI.create("file:///"); //本地文件系统的uri scheme
  private Path workingDir;  /**
* Creates the specified directory hierarchy. Does not
* treat existence as an error.
*/
//递归创建目录,是个幂等操作
public boolean mkdirs(Path f) throws IOException {
Path parent = f.getParent();
File p2f = pathToFile(f); //如果父目录为空,试图先创建父目录
//通过File创建目录,并判断成功创建目录
return (parent == null || mkdirs(parent)) &&
(p2f.mkdir() || p2f.isDirectory());
} /** {@inheritDoc} */
//递归创建目录,并为目录设置访问权限(通过调用shell的"chmod "命令来完成的)
//问答:奇怪java的文件操作中没有提供chmod的api吗???查看java.io.File后发现提供了相应的api,
//但控制粒度太粗了,相关api为:setReadOnly,setWritable,setReadable,setExecutable。对用户权限的控制只到了owner和other的区分对待,没有“chmod ”控制的精细
@Override
public boolean mkdirs(Path f, FsPermission permission) throws IOException {
boolean b = mkdirs(f);
setPermission(f, permission);
return b;
}

再看一下RawLocalFileSystem中的一个内部类RowLocalFileStatus:

 static class RawLocalFileStatus extends FileStatus {
/* We can add extra fields here. It breaks at least CopyFiles.FilePair().
* We recognize if the information is already loaded by check if
* onwer.equals("").
*/
private boolean isPermissionLoaded() {
return !super.getOwner().equals("");
} RawLocalFileStatus(File f, long defaultBlockSize, FileSystem fs) {
super(f.length(), f.isDirectory(), 1, defaultBlockSize,
f.lastModified(), new Path(f.getPath()).makeQualified(fs));
} @Override
public FsPermission getPermission() {
if (!isPermissionLoaded()) {
loadPermissionInfo();
}
return super.getPermission();
}   //使用'ls -ld'命令来获取权限信息
private void loadPermissionInfo() {
IOException e = null;
try {
StringTokenizer t = new StringTokenizer(
FileUtil.execCommand(new File(getPath().toUri()),
Shell.getGET_PERMISSION_COMMAND()));
//expected format
//-rw------- 1 username groupname ...
String permission = t.nextToken();
if (permission.length() > 10) { //files with ACLs might have a '+'
permission = permission.substring(0, 10);
}
setPermission(FsPermission.valueOf(permission));
t.nextToken();
setOwner(t.nextToken());
setGroup(t.nextToken());
} catch (Shell.ExitCodeException ioe) {
if (ioe.getExitCode() != 1) {
e = ioe;
} else {
setPermission(null);
setOwner(null);
setGroup(null);
}
} catch (IOException ioe) {
e = ioe;
} finally {
if (e != null) {
throw new RuntimeException("Error while running command to get " +
"file permissions : " +
StringUtils.stringifyException(e));
}
}
}

通过以上两段代码可以看出hadoop的本地文件系统的实现,在利用java语言提供的File类的基础上,做了一些适合自身的变化来达到目标。调用linux的shell命令,需要在linux系统中创建一个新的java虚拟机而消耗大量的资源。

2. 文件的读分析

RawLocalFileSystem使用LocalFSFileInputStream和LocalFSFileOutputStream进行读写。

/*******************************************************
* For open()'s FSInputStream
*******************************************************/
//本地文件系统读取流
class LocalFSFileInputStream extends FSInputStream {
FileInputStream fis; //文件读取流
private long position; //记录当前读取的数据在文件中的位置 public LocalFSFileInputStream(Path f) throws IOException {
this.fis = new TrackingFileInputStream(pathToFile(f)); //实际使用的是文件读取流是TrackingFileInputStream
} //系统文件当前位置
public void seek(long pos) throws IOException {
fis.getChannel().position(pos);
this.position = pos;
} //获取位置
public long getPos() throws IOException {
return this.position;
} //定位到新的block(本地文件系统没有这样的功能,所以简单返回失败)
public boolean seekToNewSource(long targetPos) throws IOException {
return false;
} /*
* Just forward to the fis
*/
//获取剩余可读或可跳过的字节数
public int available() throws IOException { return fis.available(); }
//关闭输入流,并释放系统分配的资源
public void close() throws IOException { fis.close(); }
public boolean markSupport() { return false; } //read()方法需要随时更新position,以保证getPos()能返回正确的值
public int read() throws IOException {
try {
int value = fis.read();
if (value >= 0) {
this.position++; //更新文件当前位置
}
return value;
} catch (IOException e) { // unexpected exception
throw new FSError(e); // assume native fs error
}
} public int read(byte[] b, int off, int len) throws IOException {
try {
int value = fis.read(b, off, len);
if (value > 0) {
this.position += value;
}
return value;
} catch (IOException e) { // unexpected exception
throw new FSError(e); // assume native fs error
}
} public int read(long position, byte[] b, int off, int len)
throws IOException {
ByteBuffer bb = ByteBuffer.wrap(b, off, len);
try {
return fis.getChannel().read(bb, position);
} catch (IOException e) {
throw new FSError(e);
}
} public long skip(long n) throws IOException {
long value = fis.skip(n);
if (value > 0) {
this.position += value;
}
return value;
}
}

可以看到LocalFSFileInputStream类实际使用的读流是TrackingFileInputStream

//重写了FileInputStream中的所有read方法,提供文件读取字节数的统计功能。
//TrackingFileInputStream使用修饰器模式
class TrackingFileInputStream extends FileInputStream {
public TrackingFileInputStream(File f) throws IOException {
super(f);
} public int read() throws IOException {
int result = super.read();
if (result != -1) {
statistics.incrementBytesRead(1);
}
return result;
} public int read(byte[] data) throws IOException {
int result = super.read(data);
if (result != -1) {
statistics.incrementBytesRead(result);
}
return result;
} public int read(byte[] data, int offset, int length) throws IOException {
int result = super.read(data, offset, length);
if (result != -1) {
statistics.incrementBytesRead(result);
}
return result;
}
}

那么RawLocalFileSystem和LocalFSFileInputStream是如何对接起来进行读操作的呢,当然还是和java的api一致(使用open()和create()方法来创建LocalFSFileInputStream)。下面以LocalFSFileInputStream的open()方法为例进行分析:

public FSDataInputStream open(Path f, int bufferSize) throws IOException {
if (!exists(f)) {
throw new FileNotFoundException(f.toString());
}
return new FSDataInputStream(new BufferedFSInputStream( //包装LocalFSFileInputStream
new LocalFSFileInputStream(f), bufferSize));
}
public class FSDataInputStream extends DataInputStream
implements Seekable, PositionedReadable, Closeable { public FSDataInputStream(InputStream in)
throws IOException {
super(in);
if( !(in instanceof Seekable) || !(in instanceof PositionedReadable) ) {
throw new IllegalArgumentException(
"In is not an instance of Seekable or PositionedReadable");
}
} public synchronized void seek(long desired) throws IOException {
((Seekable)in).seek(desired);
} public long getPos() throws IOException {
return ((Seekable)in).getPos();
} public int read(long position, byte[] buffer, int offset, int length)
throws IOException {
return ((PositionedReadable)in).read(position, buffer, offset, length);
} public void readFully(long position, byte[] buffer, int offset, int length)
throws IOException {
((PositionedReadable)in).readFully(position, buffer, offset, length);
} public void readFully(long position, byte[] buffer)
throws IOException {
((PositionedReadable)in).readFully(position, buffer, 0, buffer.length);
} public boolean seekToNewSource(long targetPos) throws IOException {
return ((Seekable)in).seekToNewSource(targetPos);
}
}

获取到读流后就可以调用流的读取方法进行读取了。

3. 文件的写分析

至于写操作,还是和java中的写保持一致的,支持append和随机写两种方式。

hadoop源码剖析--RawLocalFileSystem的更多相关文章

  1. hadoop源码剖析--hdfs安全模式

    一.什么是安全模式 hadoop安全模式是name node的一种状态,处于该状态时有种量特性: 1.namenode不接受任何对hfds文件系统的改变操作(即此时整个文件系统处于只读状态): 2.不 ...

  2. hadoop源码剖析--$HADOOP_HOME/bin/hadoop脚本文件分析

    1. $HADOOP_HOME/bin/ hadoop #!/usr/bin/env bash# Licensed to the Apache Software Foundation (ASF) un ...

  3. (升级版)Spark从入门到精通(Scala编程、案例实战、高级特性、Spark内核源码剖析、Hadoop高端)

    本课程主要讲解目前大数据领域最热门.最火爆.最有前景的技术——Spark.在本课程中,会从浅入深,基于大量案例实战,深度剖析和讲解Spark,并且会包含完全从企业真实复杂业务需求中抽取出的案例实战.课 ...

  4. Hadoop源码学习笔记之NameNode启动场景流程二:http server启动源码剖析

    NameNodeHttpServer启动源码剖析,这一部分主要按以下步骤进行: 一.源码调用分析 二.伪代码调用流程梳理 三.http server服务流程图解 第一步,源码调用分析 前一篇文章已经锁 ...

  5. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  6. 《Apache Spark源码剖析》

    Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...

  7. Spark源码剖析 - SparkContext的初始化(二)_创建执行环境SparkEnv

    2. 创建执行环境SparkEnv SparkEnv是Spark的执行环境对象,其中包括众多与Executor执行相关的对象.由于在local模式下Driver会创建Executor,local-cl ...

  8. Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍

    最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...

  9. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

随机推荐

  1. leetcode 题解 || Remove Nth Node From End of List 问题

    problem: Given a linked list, remove the nth node from the end of list and return its head. For exam ...

  2. select中分割多组option

    <optgroup style="color:gray; font-style:normal" label="——雪佛兰(五菱)——"></o ...

  3. 使mysql按中文字段排序

    http://ourmysql.com/archives/391   测试后我发现,gbk不仅对字符内容是按拼音排序的,对数字也是一样,使用时需注意!     另外一篇文章: MySQL按中文拼音排序

  4. POJ 3580(SuperMemo-Splay区间加)[template:Splay V2]

    SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11384   Accepted: 3572 Case T ...

  5. YUV格式

    http://blog.csdn.net/u011270282/article/details/50696616 http://blog.csdn.net/acs713/article/details ...

  6. 两个经典的文件IO程序示例

    前言 本文分析两个经典的C++文件IO程序,提炼出其中文件IO的基本套路,留待日后查阅. 程序功能 程序一打印用户指定的所有文本文件,程序二向用户指定的所有文本文件中写入数据. 程序一代码及其注释 # ...

  7. Android-Bundle的说明和用法

    1.Bundle类的作用 Bundle类是一种数据载体,类似于Map,用于存放key-value名值对形式的值.相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法, 如:put ...

  8. iOS开发之加载、滑动翻阅大量图片优化解决方案

    本文转载至 http://mobile.51cto.com/iphone-413267.htm 今天分享一下私人相册中,读取加载.滑动翻阅大量图片解决方案,我想强调的是,编程思想无关乎平台限制.我要详 ...

  9. spring源码解析——2容器的基本实现(第2版笔记)

    感觉第二版写的略潦草,就是在第一版的基础上加上了新的流行特性,比如idea,springboot,但是,潦草痕迹遍布字里行间. 虽然换成了idea,但是很多截图还是eclipse的,如果不是看了第一版 ...

  10. mac gem命令

    $ gem sources -r https://rubygems.org/ (移除旧版本的镜像,如果你不知道你电脑上目前用的是什么镜像,可用  $ gem sources -l  来查看)  $ g ...