hadoop Path由来用法示例源码详解
由来
Hadoop Path是Hadoop文件系统(HDFS)中文件和目录的抽象表示。它由Hadoop核心库提供,并用于处理Hadoop分布式文件系统中的文件路径。
Path类的设计受到了Unix文件系统路径的启发,它使用斜杠(/)作为分隔符来表示层次结构路径。与Unix路径不同的是,Hadoop Path可以引用不同的文件系统,如本地文件系统、HDFS以及其他支持的文件系统,因此它还包含有关文件系统方案和权限的信息。
作用
Path类的主要作用是:
- 表示文件和目录的路径,可以指定绝对路径或相对路径。
- 提供方法来操作路径,如获取路径的父级、获取路径的最后一个组件、比较路径等。
- 与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");
}
}