linux用户身份与群组记录的文件

cat /etc/group                查看用户组
 cat /etc/shadow              查看个人密码
 cat /etc/passwd              查看用户相关信息

这三个文件可以说是:账号,密码,群组    信息的的集中地!

w或who                            查看用户在线信息和登录信息

eclipse 创建方法快捷键shift + alt + M  
eclipse 创建局部变量快捷键 shift + alt + L

1.对hdfs的操作方式:hadoop fs xxx

hadoop fs -ls  /    查看hdfs的根目录下的内容的 
   hadoop fs -lsr /    递归查看hdfs的根目录下的内容的 
   hadoop fs -mkdir /d1    在hdfs上创建文件夹d1 
   hadoop fs -put <linux source> <hdfs destination> 把数据从linux上传到hdfs的特定路径中 
   hadoop fs -get <hdfs source> <linux destination> 把数据从hdfs下载到linux的特定路径下 
   hadoop fs -text <hdfs文件>    查看hdfs中的文件 
   hadoop fs -rm        删除hdfs中文件 
   hadoop fs -rmr    删除hdfs中的文件夹 
  
   hadoop fs -ls hdfs://zebra:9000/

 

2.HDFS的datanode在存储数据时,如果原始文件大小>64MB,按照64MB大小切分;如果<64MB,只有一个block,占用磁盘空间是源文件实际大小。

下面学习搭建Hadoop开发环境(伪分布模式),练习HDFS 的java访问方法,具体搭建方法网上很多,这里不是多说,有一点需要注意,就是我们本地跑hadoop项目需要将它的权限注释掉,避免权限错误,报权限异常,做法就是对包core里的org.apache.hadoop.fs.FileUtil 类的 checkReturnValue 方法内容注释,如下:

private static void checkReturnValue(boolean rv, File p, 
                                       FsPermission permission
                                       ) throws IOException {
//	  //权限屏蔽,zebra 
//    if (!rv) {
//      throw new IOException("Failed to set permissions of path: " + p + 
//                            " to " + 
//                            String.format("%04o", permission.toShort()));
//    }
  }

接着我们讲HDFS的java操作,这就需要使用FileSystem api读写数据,它是org.apache.hadoop.fs.FileSystem,这是我们用户代码操作 HDFS 的直接入口,该类含有操作 HDFS 的各种方法,类似于 jdbc 中操作数据库的直接入口是Connection 类。

详细的读写操作,我在下面的代码中逐个说明。这里附上自己的操作代码:

package com.zeb;

import java.io.ByteArrayInputStream;
import java.net.URI;

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;
import org.apache.hadoop.io.IOUtils;

public class fileSystemApi {
    private static final String uri = "hdfs://zebra:9000/";

    //org.apache.hadoop.fs.FileSystem是一个重要的api,他是用户操作hdfs的直接入口,类似与jdbc操作数据库的Connection类。
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        //fileSystem的静态方法get传递两个值给形式参数,第一个是访问HDFS的地址,该地址的协议是hdfs,
        //ip是zebra:9000。,这个地址的完整信息在配置文件core-site.xml中指定,第二个参数是一个配置对象
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        
        //eclipse 创建方法快捷键shift + alt + M
        //eclipse 创建局部变量快捷键 shift + alt + L
//        //创建一个文件夹
//        final String pathString ="/zhang1";
//        Path path = new Path(pathString);
//        boolean exits = fs.exists(path);
//        if(!exits){//判断文件夹是否存在
//            boolean result = fs.mkdirs(path);
//            System.out.println(result);//返回布尔值,true or false.
//        }
        
//        //创建一个文件,并写入一些信息
//        final String pathString = "/zhang/zebraText";
//        Path path = new Path(pathString);
//        //FSDataOutputStream调用 create 方法创建一个通向 HDFS 的输出流;
//        final FSDataOutputStream fdos = fs.create(path);
//        //通过调用 hadoop 的一个工具类 IOUtils 的静态方法 copyBytes 把一个字符串发
//        //送给输出流中。该静态方法有四个参数,第一个参数输入流,第二个参数是输出流,第三个
//        //参数是配置对象,第四个参数是布尔值,如果是 true 表示数据传输完毕后关闭流。
//        IOUtils.copyBytes(new ByteArrayInputStream("This is the first try!".getBytes()), fdos, conf, true);
        
//        //读取刚才写入的文件信息
//        final String pathString = "/zhang/zebraText";
//        //FSDataInputStream调用方法 open 打开一个指定的文件,返回值是一个通向该文件的输入流;
//        final FSDataInputStream fdis = fs.open(new Path(pathString));
//        //通过调用 IOUtils.copyBytes 方法,输出的目的地是控制台。
//        IOUtils.copyBytes(fdis, System.out, conf, true);
        
        //查看目录文件列表和文件详细信息
//        final String pathString = "/";
//        Path path = new Path(pathString);
//        //调用listStatus方法会得到一个指定路径下的所有文件和文件夹,每一个用FileStatus表示。我
//        //们使用for循环显示每一个FileStatus对象。FileStatus对象表示文件的详细信息,里面含有类型、
//        //副本数、权限、长度、路径等很多信息
//        final FileStatus[] listStatus = fs.listStatus(path);
//        for(FileStatus fstatus : listStatus){
//            final String type = fstatus.isDir()?"目录":"文件";
//            final short replication = fstatus.getReplication();
//            final String permission = fstatus.getPermission().toString();
//            final Long len = fstatus.getLen();
//            final Path p = fstatus.getPath();
//            System.out.println(type+"\t"+permission+"\t"+replication+"\t"+len+"\t"+p);
//        }
        
//        //删除文件
//        final String pathString = "/zhang/zebraText";
//        Path path =new Path(pathString);
//        //递归删除目录“/zhang”及下面的所有内容
//        fs.delete(new Path("/zhang"), true);
//        //删除文件/zhang/zebraText
        fs.deleteOnExit(path);
    }
}



HDFS的写数据过程分析:

我们通过 FileSystem 类可以操控 HDFS,那我们就从这里开始分析写数据到 HDFS 的过程。在我们向 HDFS 写文件的时候,调用的是 FileSystem.create(Path path)方法,我们查看这个方法的源码,通过跟踪内部的重载方法,可以找到它最终调用的抽象方法,如下源码。

/**
   * Opens an FSDataOutputStream at the indicated Path with write-progress
   * reporting.
   * @param f the file name to open
   * @param permission
   * @param overwrite if a file with this name already exists, then if true,
   *   the file will be overwritten, and if false an error will be thrown.
   * @param bufferSize the size of the buffer to be used.
   * @param replication required block replication for the file.
   * @param blockSize
   * @param progress
   * @throws IOException
   * @see #setPermission(Path, FsPermission)
   */
  public abstract FSDataOutputStream create(Path f,
      FsPermission permission,
      boolean overwrite,
      int bufferSize,
      short replication,
      long blockSize,
      Progressable progress) throws IOException;


这个方法是抽象类,没有实现。那么我们只能向他的子类寻找实现。FileSystem 有个子类是 DistributedFileSystem,在 我们的 伪分布环 境下使 用的就 是这个 类。我 们可以看 到DistributedFileSystem 的这个方法的实现(ctrl + T),如图。

public FSDataOutputStream create(Path f, FsPermission permission,
    boolean overwrite,
    int bufferSize, short replication, long blockSize,
    Progressable progress) throws IOException {

    statistics.incrementWriteOps(1);
    return new FSDataOutputStream
       (dfs.create(getPathName(f), permission,
                   overwrite, true, replication, blockSize, progress, bufferSize),
        statistics);
  }


注意它的返回值 FSDataOutputStream。这个返回值对象调用了自己的构造方法,构造方法的第一个参数是 dfs.create()方法。我们关注一下这里的 dfs 对象是谁,create 方法做了什么事情。现在进入这个方法的实现,如图。

/**
   * Create a new dfs file with the specified block replication 
   * with write-progress reporting and return an output stream for writing
   * into the file.  
   * 
   * @param src stream name
   * @param permission The permission of the directory being created.
   * If permission == null, use {@link FsPermission#getDefault()}.
   * @param overwrite do not check for file existence if true
   * @param createParent create missing parent directory if true
   * @param replication block replication
   * @return output stream
   * @throws IOException
   * @see ClientProtocol#create(String, FsPermission, String, boolean, short, long)
   */
  public OutputStream create(String src, 
                             FsPermission permission,
                             boolean overwrite, 
                             boolean createParent,
                             short replication,
                             long blockSize,
                             Progressable progress,
                             int buffersize
                             ) throws IOException {
    checkOpen();
    if (permission == null) {
      permission = FsPermission.getDefault();
    }
    FsPermission masked = permission.applyUMask(FsPermission.getUMask(conf));
    LOG.debug(src + ": masked=" + masked);
    final DFSOutputStream result = new DFSOutputStream(src, masked,
        overwrite, createParent, replication, blockSize, progress, buffersize,
        conf.getInt("io.bytes.per.checksum", 512));
    beginFileLease(src, result);
    return result;
  }


返回值正是创建的对象。这个类有什么神奇的地方吗?我们看一下他的源码,如图。

/**
     * Create a new output stream to the given DataNode.
     * @see ClientProtocol#create(String, FsPermission, String, boolean, short, long)
     */
    DFSOutputStream(String src, FsPermission masked, boolean overwrite,
        boolean createParent, short replication, long blockSize, Progressable progress,
        int buffersize, int bytesPerChecksum) throws IOException {
      this(src, blockSize, progress, bytesPerChecksum, replication);

      computePacketChunkSize(writePacketSize, bytesPerChecksum);

      try {
        // Make sure the regular create() is done through the old create().
        // This is done to ensure that newer clients (post-1.0) can talk to
        // older clusters (pre-1.0). Older clusters lack the new  create()
        // method accepting createParent as one of the arguments.
        if (createParent) {
          namenode.create(
            src, masked, clientName, overwrite, replication, blockSize);
        } else {
          namenode.create(
            src, masked, clientName, overwrite, false, replication, blockSize);
        }
      } catch(RemoteException re) {
        throw re.unwrapRemoteException(AccessControlException.class,
                                       FileAlreadyExistsException.class,
                                       FileNotFoundException.class,
                                       NSQuotaExceededException.class,
                                       DSQuotaExceededException.class);
      }
      streamer.start();
    }


可 以 看 到 , 这 个 类 是 DFSClient 的 内 部 类 。 在 类 内 部 通 过 调 用namenode.create()方法创建了一个输出流。我们再看一下 namenode 对象是什么类型,发现是  public final ClientProtocol namenode;是 ClientProtocal 接口。那么,这个对象是什么时候创建的那?如图

hadoop启动需要密码 hadoop忘记密码_分布式文件系统

namenode 对象是在 DFSClient 的构造函数调用时创建的,即当 DFSClient 对象存在的时候,namenode 对象已经存在了。
至此,我们可以看到,使用 FileSystem 对象的 api 操纵 HDFS,其实是通过 DFSClient 对象访问 NameNode 中的方法操纵 HDFS 的。这里的 DFSClient 是 RPC 机制的客户端, NameNode是 RPC 机制的服务端的调用对象,整个调用过程如图。

hadoop启动需要密码 hadoop忘记密码_分布式文件系统_02

在整个过程中,DFSClient 是个很重要的类,从名称就可以看出,他表示 HDFS 的 Client,是整个 HDFS 的 RPC 机制的客户端部分。我们对 HDFS 的操作,是通过 FileSsytem 调用的DFSClient 里面的方法。FileSystem 是封装了对 DFSClient 的操作,提供给用户使用的。HDFS的读操作也是这样,调用的open(path)方法,这里不多分析,今天就总结到这里。