hadoop Path用法示例源码详解

50 篇文章 0 订阅

hadoop Path由来用法示例源码详解

由来

Hadoop Path是Hadoop文件系统(HDFS)中文件和目录的抽象表示。它由Hadoop核心库提供,并用于处理Hadoop分布式文件系统中的文件路径。

Path类的设计受到了Unix文件系统路径的启发,它使用斜杠(/)作为分隔符来表示层次结构路径。与Unix路径不同的是,Hadoop Path可以引用不同的文件系统,如本地文件系统、HDFS以及其他支持的文件系统,因此它还包含有关文件系统方案和权限的信息。

作用

Path类的主要作用是

  1. 表示文件和目录的路径,可以指定绝对路径或相对路径。
  2. 提供方法来操作路径,如获取路径的父级、获取路径的最后一个组件、比较路径等。
  3. 与FileSystem类一起使用,用于创建文件系统对象、打开文件、读取数据等操作。

在Hadoop中,Path类广泛用于处理文件系统中的路径信息。它在MapReduce作业、Hive查询、Spark应用程序等各种大数据处理场景中都被频繁使用。

总之,Hadoop Path是Hadoop文件系统中文件和目录的抽象表示,它提供了操作路径的方法,并与FileSystem类一起使用来进行文件系统的访问和操作。

方法总结

方法描述
int compareTo(Path o)比较此路径与给定路径的顺序。
int depth()返回此路径中的元素数。
boolean equals(Object o)判断此路径是否与给定对象相等。
FileSystem getFileSystem(Configuration conf)返回拥有此路径的FileSystem。
String getName()返回此路径的最后一个组件。
Path getParent()返回路径的父级,如果在根目录,则返回null。
static Path getPathWithoutSchemeAndAuthority(Path path)返回不带方案信息的给定路径的版本。
int hashCode()返回此路径的哈希码值。
boolean isAbsolute()判断路径是否为绝对路径。
boolean isAbsoluteAndSchemeAuthorityNull()判断路径是否为绝对路径且没有方案和权限。
boolean isRoot()判断路径是否为文件系统的根。
boolean isUriPathAbsolute()判断路径是否为URI路径的绝对路径。
static boolean isWindowsAbsolutePath(String pathString, boolean slashed)判断给定路径字符串是否表示Windows上的绝对路径。
Path makeQualified(FileSystem fs)获取路径在指定文件系统中的限定路径。
static Path mergePaths(Path path1, Path path2)合并两个路径,将第二个路径附加到第一个路径中。
Path suffix(String suffix)将后缀添加到路径的最后一个组件。
String toString()将路径转换为字符串表示。
URI toUri()将路径转换为URI。
void validateObject()验证反序列化路径的内容,以防止恶意对象流。

示例

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.io.IOException;
import java.net.URI;

public class PathExample {
    public static void main(String[] args) {
        // 创建配置对象
        Configuration conf = new Configuration();

        // 创建路径对象
        Path path = new Path("/user/hadoop/input/file.txt");

        // 比较路径
        Path anotherPath = new Path("/user/hadoop/output/file.txt");
        int compareResult = path.compareTo(anotherPath);
        System.out.println("Compare Result: " + compareResult);

        // 获取路径的深度
        int depth = path.depth();
        System.out.println("Depth: " + depth);

        // 判断路径是否相等
        boolean isEqual = path.equals(anotherPath);
        System.out.println("Is Equal: " + isEqual);

        try {
            // 获取拥有此路径的FileSystem
            FileSystem fileSystem = path.getFileSystem(conf);
            System.out.println("FileSystem: " + fileSystem);

            // 获取路径的最后一个组件
            String name = path.getName();
            System.out.println("Name: " + name);

            // 获取路径的父级
            Path parent = path.getParent();
            System.out.println("Parent: " + parent);

            // 将路径转换为URI
            URI uri = path.toUri();
            System.out.println("URI: " + uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//Compare Result: -6
//Depth: 4
//Is Equal: false
//FileSystem: org.apache.hadoop.fs.LocalFileSystem@2a32de6c
//Name: file.txt
//Parent: /user/hadoop/input
//URI: /user/hadoop/input/file.txt

源码

import java.org.apache.hadoop.shaded.io.IOException;
import java.org.apache.hadoop.shaded.io.InvalidObjectException;
import java.org.apache.hadoop.shaded.io.ObjectInputValidation;
import java.org.apache.hadoop.shaded.io.Serializable;
import java.org.apache.hadoop.shaded.net.URI;
import java.org.apache.hadoop.shaded.net.URISyntaxException;
import java.util.regex.Pattern;

import org.apache.hadoop.shaded.org.apache.avro.reflect.Stringable;
import org.apache.hadoop.shaded.org.apache.org.apache.hadoop.shaded.com.ons.lang3.StringUtils;
import org.apache.hadoop.shaded.org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.shaded.org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.shaded.org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.shaded.org.apache.hadoop.conf.Configuration;

/**
 * 在{@link FileSystem}中命名文件或目录的路径。
 * 路径字符串使用斜杠作为目录分隔符。
 */
@Stringable
@InterfaceAudience.Public
@InterfaceStability.Stable
public class Path
    implements Comparable<Path>, Serializable, ObjectInputValidation {

  /**
   * 目录分隔符,一个斜杠。
   */
  public static final String SEPARATOR = "/";

  /**
   * 目录分隔符,一个斜杠,作为字符。
   */
  public static final char SEPARATOR_CHAR = '/';
  
  /**
   * 当前目录,"。"
   */
  public static final String CUR_DIR = ".";
  
  /**
   * 当前主机是否为Windows机器。
   */
  public static final boolean WINDOWS =
      System.getProperty("os.name").startsWith("Windows");

  /**
   * 用于检测路径格式的预编译正则表达式。
   */
  private static final Pattern HAS_DRIVE_LETTER_SPECIFIER =
      Pattern.org.apache.hadoop.shaded.com.ile("^/?[a-zA-Z]:");

  /** 用于检测重复斜线的预编译正则表达式。 */
  private static final Pattern SLASHES = Pattern.org.apache.hadoop.shaded.com.ile("/+");

  private static final long serialVersionUID = 0xad00f;

  private URI uri; // 分层uri

  /**
   * 检查此路径是否使用方案并且是相对的。
   * 带有方案和相对路径的路径名是非法的。
   */
  void checkNotSchemeWithRelative() {
    if (toUri().isAbsolute() && !isUriPathAbsolute()) {
      throw new HadoopIllegalArgumentException(
          "Unsupported name: has scheme but relative path-part");
    }
  }

  void checkNotRelative() {
    if (!isAbsolute() && toUri().getScheme() == null) {
      throw new HadoopIllegalArgumentException("Path is relative");
    }
  }

  /**
   * 返回一个不包含方案信息的给定路径的副本。
   *
   * @param path 源路径
   * @return 不包含方案信息的此路径的副本
   */
  public static Path getPathWithoutSchemeAndAuthority(Path path) {
    // 此代码依赖于Path.toString()在Windows之前删除驱动器规范之前删除前导斜杠。
    Path newPath = path.isUriPathAbsolute() ?
      new Path(null, null, path.toUri().getPath()) :
      path;
    return newPath;
  }

  /**
   * 根据相对于父路径解析的子路径创建新路径。
   *
   * @param parent 父路径
   * @param child 子路径
   */
  public Path(String parent, String child) {
    this(new Path(parent), new Path(child));
  }

  /**
   * 根据相对于父路径解析的子路径创建新路径。
   *
   * @param parent 父路径
   * @param child 子路径
   */
  public Path(Path parent, String child) {
    this(parent, new Path(child));
  }

  /**
   * 根据相对于父路径解析的子路径创建新路径。
   *
   * @param parent 父路径
   * @param child 子路径
   */
  public Path(String parent, Path child) {
    this(new Path(parent), child);
  }

  /**
   * 根据相对于父路径解析的子路径创建新路径。
   *
   * @param parent 父路径
   * @param child 子路径
   */
  public Path(Path parent, Path child) {
    // 向父级路径添加斜杠,以使解析与URI的org.apache.hadoop.shaded.com.atible
    URI parentUri = parent.uri;
    String parentPath = parentUri.getPath();
    if (!(parentPath.equals("/") || parentPath.isEmpty())) {
      try {
        parentUri = new URI(parentUri.getScheme(), parentUri.getAuthority(),
                      parentUri.getPath()+"/", null, parentUri.getFragment());
      } catch (URISyntaxException e) {
        throw new IllegalArgumentException(e);
      }
    }
    URI resolved = parentUri.resolve(child.uri);
    initialize(resolved.getScheme(), resolved.getAuthority(),
               resolved.getPath(), resolved.getFragment());
  }

  private void checkPathArg( String path ) throws IllegalArgumentException {
    // 禁止使用空字符串构建路径
    if ( path == null ) {
      throw new IllegalArgumentException(
          "Can not create a Path from a null string");
    }
    if( path.length() == 0 ) {
       throw new IllegalArgumentException(
           "Can not create a Path from an empty string");
    }   
  }
  
  /**
   * 从字符串创建路径。路径字符串是URI,但是没有转义的元素和一些附加的标准化。
   *
   * @param pathString 路径字符串
   */
  public Path(String pathString) throws IllegalArgumentException {
    checkPathArg( pathString );
    
    // 我们不能直接使用'new URI(String)',因为它假设事物都已转义,
    // 而我们不要求Paths转义。

    // 在具有Windows驱动器字母的路径前面添加斜杠
    if (hasWindowsDrive(pathString) && pathString.charAt(0) != '/') {
      pathString = "/" + pathString;
    }

    // 解析uri的组件
    String scheme = null;
    String authority = null;

    int start = 0;

    // 解析uri方案(如果有)
    int colon = pathString.indexOf(':');
    int slash = pathString.indexOf('/');
    if ((colon != -1) &&
        ((slash == -1) || (colon < slash))) {     // 有方案
      scheme = pathString.substring(0, colon);
      start = colon+1;
    }

    // 解析uri授权(如果有)
    if (pathString.startsWith("//", start) &&
        (pathString.length()-start > 2)) {       // 有授权
      int nextSlash = pathString.indexOf('/', start+2);
      int authEnd = nextSlash > 0 ? nextSlash : pathString.length();
      authority = pathString.substring(start+2, authEnd);
      start = authEnd;
    }

    // uri路径是字符串的剩余部分 - 不支持查询和片段
    String path = pathString.substring(start, pathString.length());

    initialize(scheme, authority, path, null);
  }

  /**
   * 根据URI创建路径
   *
   * @param aUri 源URI
   */
  public Path(URI aUri) {
    uri = aUri.normalize();
  }
  
  /**
   * 根据org.apache.hadoop.shaded.com.onents创建路径。
   *
   * @param scheme 方案
   * @param authority 授权
   * @param path 路径
   */
  public Path(String scheme, String authority, String path) {
    checkPathArg( path );

    // 在具有Windows驱动器字母的路径前面添加斜杠
    if (hasWindowsDrive(path) && path.charAt(0) != '/') {
      path = "/" + path;
    }

    // 在Linux相对路径前面添加"./",以便不会将包含冒号的路径(例如"a:b")解释为方案"a"。
    if (!WINDOWS && path.charAt(0) != '/') {
      path = "./" + path;
    }

    initialize(scheme, authority, path, null);
  }

  private void initialize(String scheme, String authority, String path,
      String fragment) {
    try {
      this.uri = new URI(scheme, authority, normalizePath(scheme, path), null, fragment)
        .normalize();
    } catch (URISyntaxException e) {
      throw new IllegalArgumentException(e);
    }
  }

  /**
   * 合并两个路径,使第二个路径相对于第一个路径添加。
   * 返回的路径具有第一个路径的方案和授权。在Windows上,丢弃第二个路径中的驱动器规范。
   * 
   * @param path1 第一个路径
   * @param path2 要附加到path1的第二个路径
   * @return 合并后的路径
   */
  public static Path mergePaths(Path path1, Path path2) {
    String path2Str = path2.toUri().getPath();
    path2Str = path2Str.substring(startPositionWithoutWindowsDrive(path2Str));
    // 明确添加路径org.apache.hadoop.shaded.com.onents,因为简单地连接两个路径字符串是不安全的,例如:
    // "/" + "/foo"产生"//foo",这将被解析为Path中的授权
    return new Path(path1.toUri().getScheme(), 
        path1.toUri().getAuthority(), 
        path1.toUri().getPath() + path2Str);
  }

  /**
   * 将路径字符串规范化为使用非重复的前斜杠作为路径分隔符,并删除任何尾部路径分隔符。
   *
   * @param scheme URI方案。用于推断我们是否应该替换反斜杠
   * @param path 方案特定部分
   * @return 规范化的路径字符串
   */
  private static String normalizePath(String scheme, String path) {
    // 删除重复的斜线。
    path = SLASHES.matcher(path).replaceAll("/");

    // 如果这看起来像Windows路径,请删除反斜杠。如果看起来像非本地URI,请避免替换。
    if (WINDOWS &&
        (hasWindowsDrive(path) ||
         (scheme == null) ||
         (scheme.isEmpty()) ||
         (scheme.equals("file")))) {
      path = StringUtils.replace(path, "\\", "/");
    }
    
    // 从非根路径中删除尾部斜杠(忽略Windows驱动器)
    int minLength = startPositionWithoutWindowsDrive(path) + 1;
    if (path.length() > minLength && path.endsWith(SEPARATOR)) {
      path = path.substring(0, path.length()-1);
    }
    
    return path;
  }

  private static boolean hasWindowsDrive(String path) {
    return (WINDOWS && HAS_DRIVE_LETTER_SPECIFIER.matcher(path).find());
  }

  private static int startPositionWithoutWindowsDrive(String path) {
    if (hasWindowsDrive(path)) {
      return path.charAt(0) ==  SEPARATOR_CHAR ? 3 : 2;
    } else {
      return 0;
    }
  }
  
  /**
   * 确定给定路径字符串是否表示Windows上的绝对路径。例如,"C:/a/b"是绝对路径,而"C:a/b"不是。
   *
   * @param pathString 要评估的路径字符串
   * @param slashed 如果给定路径以"/"为前缀,则为true
   * @return 如果提供的路径看起来是带有Windows驱动器规范的绝对路径,则为true
   */
  public static boolean isWindowsAbsolutePath(final String pathString,
                                              final boolean slashed) {
    int start = startPositionWithoutWindowsDrive(pathString);
    return start > 0
        && pathString.length() > start
        && ((pathString.charAt(start) == SEPARATOR_CHAR) ||
            (pathString.charAt(start) == '\\'));
  }

  /**
   * 将此Path转换为URI。
   *
   * @return 此Path作为URI
   */
  public URI toUri() { return uri; }

  /**
   * 返回拥有此Path的FileSystem。
   *
   * @param conf 解析FileSystem时使用的配置
   * @return 拥有此Path的FileSystem
   * @throws java.org.apache.hadoop.shaded.io.IOException 如果解析FileSystem时出现问题
   */
  public FileSystem getFileSystem(Configuration conf) throws IOException {
    return FileSystem.get(this.toUri(), conf);
  }

  /**
   * 当前路径的目录(即文件夹)部分是否是绝对的<strong>且</strong>方案为空,<b>且</b>授权为空。
   *
   * @return 路径是否绝对,URI是否没有方案和授权部分
   */
  public boolean isAbsoluteAndSchemeAuthorityNull() {
    return  (isUriPathAbsolute() && 
        uri.getScheme() == null && uri.getAuthority() == null);
  }
  
  /**
   * 此URI的路径org.apache.hadoop.shaded.com.onent是否是绝对的。
   *
   * @return 此URI的路径是否是绝对的
   */
  public boolean isUriPathAbsolute() {
    int start = startPositionWithoutWindowsDrive(uri.getPath());
    return uri.getPath().startsWith(SEPARATOR, start);
   }
  
  /**
   * 此URI的路径org.apache.hadoop.shaded.com.onent是否是绝对的。此方法是{@link #isUriPathAbsolute()}的包装器。
   *
   * @return 此URI的路径是否是绝对的
   */
  public boolean isAbsolute() {
     return isUriPathAbsolute();
  }

  /**
   * 当且仅当此路径表示文件系统的根时,返回true。
   *
   * @return 当且仅当此路径表示文件系统的根时为true
   */
  public boolean isRoot() {
    return getParent() == null;
  }

  /**
   * 返回此路径的最后一个org.apache.hadoop.shaded.com.onent。
   *
   * @return 此路径的最后一个org.apache.hadoop.shaded.com.onent
   */
  public String getName() {
    String path = uri.getPath();
    int slash = path.lastIndexOf(SEPARATOR);
    return path.substring(slash+1);
  }

  /**
   * 返回路径的父路径,如果在根目录,则返回null。
   * @return 路径的父路径,如果在根目录,则返回null
   */
  public Path getParent() {
    String path = uri.getPath();
    int lastSlash = path.lastIndexOf('/');
    int start = startPositionWithoutWindowsDrive(path);
    if ((path.length() == start) ||               // 空路径
        (lastSlash == start && path.length() == start+1)) { // 在根目录
      return null;
    }
    String parent;
    if (lastSlash==-1) {
      parent = CUR_DIR;
    } else {
      parent = path.substring(0, lastSlash==start?start+1:lastSlash);
    }
    return new Path(uri.getScheme(), uri.getAuthority(), parent);
  }

  /**
   * 向路径的最后一个org.apache.hadoop.shaded.com.onent添加后缀。
   *
   * @param suffix 要添加的后缀
   * @return 添加了后缀的新路径
   */
  public Path suffix(String suffix) {
    return new Path(getParent(), getName()+suffix);
  }

  @Override
  public String toString() {
    // 我们不能使用uri.toString(),因为它会转义所有内容,但我们希望在字符串中不转义非法字符,以便进行全局处理等。
    StringBuilder buffer = new StringBuilder();
    if (uri.getScheme() != null) {
      buffer.append(uri.getScheme())
          .append(":");
    }
    if (uri.getAuthority() != null) {
      buffer.append("//")
          .append(uri.getAuthority());
    }
    if (uri.getPath() != null) {
      String path = uri.getPath();
      if (path.indexOf('/')==0 &&
          hasWindowsDrive(path) &&                // 有Windows驱动器
          uri.getScheme() == null &&              // 但没有方案
          uri.getAuthority() == null)             // 或授权
        path = path.substring(1);                 // 删除驱动器之前的斜杠
      buffer.append(path);
    }
    if (uri.getFragment() != null) {
      buffer.append("#")
          .append(uri.getFragment());
    }
    return buffer.toString();
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Path)) {
      return false;
    }
    Path that = (Path)o;
    return this.uri.equals(that.uri);
  }

  @Override
  public int hashCode() {
    return uri.hashCode();
  }

  @Override
  public int org.apache.hadoop.shaded.com.areTo(Path o) {
    return this.uri.org.apache.hadoop.shaded.com.areTo(o.uri);
  }

  /**
   * 返回此路径中的元素数。
   * @return 此路径中的元素数
   */
  public int depth() {
    String path = uri.getPath();
    int depth = 0;
    int slash = path.length()==1 && path.charAt(0)=='/' ? -1 : 0;
    while (slash != -1) {
      depth++;
      slash = path.indexOf(SEPARATOR, slash+1);
    }
    return depth;
  }

/**
 * 返回路径中的元素数量。
 * @return 路径中的元素数量
 */
public int depth() {
  String path = uri.getPath();
  int depth = 0;
  int slash = path.length()==1 && path.charAt(0)=='/' ? -1 : 0;
  while (slash != -1) {
    depth++;
    slash = path.indexOf(SEPARATOR, slash+1);
  }
  return depth;
}

/**
 * 返回{@link FileSystem}的工作目录的合格路径对象。
 *
 * @param fs 目标FileSystem
 * @return FileSystem的工作目录的合格路径对象
 * @deprecated 使用 {@link #makeQualified(URI, Path)} 方法代替
 */
@Deprecated
public Path makeQualified(FileSystem fs) {
  return makeQualified(fs.getUri(), fs.getWorkingDirectory());
}

/**
 * 返回一个合格的路径对象。
 *
 * @param defaultUri 如果此路径缺少方案或机构,从此URI中获取
 * @param workingDir 如果此路径不是绝对路径,则将其视为相对于此工作目录
 * @return 如果该路径包含方案和机构并且是绝对路径,则返回此路径,否则返回一个包含路径和机构并且是完全限定的新路径
 */
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
public Path makeQualified(URI defaultUri, Path workingDir ) {
  Path path = this;
  if (!isAbsolute()) {
    path = new Path(workingDir, this);
  }

  URI pathUri = path.toUri();

  String scheme = pathUri.getScheme();
  String authority = pathUri.getAuthority();
  String fragment = pathUri.getFragment();

  if (scheme != null &&
      (authority != null || defaultUri.getAuthority() == null))
    return path;

  if (scheme == null) {
    scheme = defaultUri.getScheme();
  }

  if (authority == null) {
    authority = defaultUri.getAuthority();
    if (authority == null) {
      authority = "";
    }
  }

  URI newUri = null;
  try {
    newUri = new URI(scheme, authority ,
      normalizePath(scheme, pathUri.getPath()), null, fragment);
  } catch (URISyntaxException e) {
    throw new IllegalArgumentException(e);
  }
  return new Path(newUri);
}

/**
 * 验证反序列化的路径的内容,以防止恶意对象流。
 * @throws InvalidObjectException 如果没有URI
 */
@Override
public void validateObject() throws InvalidObjectException {
  if (uri == null) {
    throw new InvalidObjectException("No URI in deserialized Path");
  }
}
etScheme();
  }

  if (authority == null) {
    authority = defaultUri.getAuthority();
    if (authority == null) {
      authority = "";
    }
  }

  URI newUri = null;
  try {
    newUri = new URI(scheme, authority ,
      normalizePath(scheme, pathUri.getPath()), null, fragment);
  } catch (URISyntaxException e) {
    throw new IllegalArgumentException(e);
  }
  return new Path(newUri);
}

/**
 * 验证反序列化的路径的内容,以防止恶意对象流。
 * @throws InvalidObjectException 如果没有URI
 */
@Override
public void validateObject() throws InvalidObjectException {
  if (uri == null) {
    throw new InvalidObjectException("No URI in deserialized Path");
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值