hadoop 打开文件输入流 源码分析

* 在hadoop中获取了filesystem之后,便可以通过这个客户端进行相关的文件操作。文件操作涉及到分布式文件系统文件流得使用,现在通过一个简单的下载代码实例进行文件流打开方法即filesystem.open的源码分析*

1、download()方法:

    /**
     * 下载方法,用输入流的形式
     * @throws IOException
     */
    public static void download() throws IOException{
        Path path = new Path("hdfs://master:9000/user/hadoop/Normaltest/gal.txt");   
        FSDataInputStream is=fs.open(path);  
        FileOutputStream os = new FileOutputStream("D:/hadoop/test.txt");  
        IOUtils.copy(is, os);  
    }

可以看到fs.open是返回一个FSDataInputStream对象进行文件的操作。

2、fs.open(path)

  /**
   * Opens an FSDataInputStream at the indicated Path.
   * @param f the file to open
   */
  public FSDataInputStream open(Path f) throws IOException {
    return open(f, getConf().getInt("io.file.buffer.size", 4096));
  }

可以看到此方法是通过定义了块大小后,继续调用实现类的open方法

3、 public FSDataInputStream open(Path f, final int bufferSize)


由代码可以看出运用了匿名类FileSystemLinkResolver的resolve方法解析,本质是调用了docall(),因此查看docall()中 dfs.open(getPathName(p), bufferSize, verifyChecksum)方法

4、 dfs.open(getPathName(p), bufferSize, verifyChecksum)

  public DFSInputStream open(String src, int buffersize, boolean verifyChecksum)
      throws IOException, UnresolvedLinkException {
    checkOpen();
    //    Get block info from namenode
    TraceScope scope = getPathTraceScope("newDFSInputStream", src);
    try {
      return new DFSInputStream(this, src, verifyChecksum);
    } finally {
      scope.close();
    }
  }

此方法通过构造方法返回了一个DFSInputStream,参数是this(DFS client)与src、是否检查校验和的标志(verifyChecksum)等

5、DFSInputStream(DFSClient dfsClient, String src, boolean verifyChecksum)

  DFSInputStream(DFSClient dfsClient, String src, boolean verifyChecksum) throws IOException, UnresolvedLinkException {
    this.dfsClient = dfsClient;
    this.verifyChecksum = verifyChecksum;
    this.src = src;
    synchronized (infoLock) {
      this.cachingStrategy = dfsClient.getDefaultReadCachingStrategy();
    }
    openInfo();
  }

此构造函数进行对一些类成员变量赋值(dfsClient、verifyChecksum、src、cachingStrategy ),还调用了openinfo进行其他变量的赋值

6、 openInfo()


此方法主要调用了 fetchLocatedBlocksAndGetLastBlockLength方法,由名字可看出这个是获取文件组成块的位置和最后一块的块大小(因为除了最后一块,其他块大小在配置文件中已经指定,默认64M)

7、fetchLocatedBlocksAndGetLastBlockLength()



由图中的红方框出可知,最终是通过成员变量dfsClient来获取文件块位置信息,而此变量是namenode的rpc代理对象,可与namenode直接通信

8、 dfsClient.getLocatedBlocks(src, 0)

  public LocatedBlocks getLocatedBlocks(String src, long start)
      throws IOException {
    return getLocatedBlocks(src, start, dfsClientConf.prefetchSize);
  }

可以看到是调用了getLocatedBlocks方法

9、public LocatedBlocks getLocatedBlocks(String src, long start, long length)

 public LocatedBlocks getLocatedBlocks(String src, long start, long length)
      throws IOException {
    TraceScope scope = getPathTraceScope("getBlockLocations", src);
    try {
      return callGetBlockLocations(namenode, src, start, length);
    } finally {
      scope.close();
    }
  }

紧跟着又调用了callGetBlockLocations方法

10、 static LocatedBlocks callGetBlockLocations(ClientProtocol namenode,String src, long start, long length)

static LocatedBlocks callGetBlockLocations(ClientProtocol namenode,
      String src, long start, long length) 
      throws IOException {
    try {
      return namenode.getBlockLocations(src, start, length);
    } catch(RemoteException re) {
      throw re.unwrapRemoteException(AccessControlException.class,
                                     FileNotFoundException.class,
                                     UnresolvedPathException.class);
    }
  }

最终是调用了namenode的getBlockLocations方法,由于是rpc机制,此方法的实现在服务器端。返回的数据包括文件包含的分块信息、如名字、块大小、块偏移、是否损坏的标志以及存在哪个主机等…拿到了所有文件块后最终的文件流也生成了

更多详细细节可参考文章:

http://www.tuicool.com/articles/Rr6JN3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值