今天好好讨论一下windows下的java文件路径,其实String path="D:\\a.cmd.txt"是合法的,String path="/D:/a.cmd.txt"和String path="D:\\\\\\\a.cmd.txt"都是合法的,
File file=new File(path);
System.out.println(file.exists());
返回都是true。
构建File对象时,
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
这里fs就是Win32FileSystem类
normalize函数
/*
* Check that the given pathname is normal. If not, invoke the real
* normalizer on the part of the pathname that requires normalization. This
* way we iterate through the whole pathname string only once.
*/
public static String normalize(String path) {
int n = path.length();
char slash = \\;
char altSlash = \\;
char prev = 0;
for (int i = 0; i < n; i++) {
char c = path.charAt(i);
if (c == altSlash)
return normalize(path, n, (prev == slash) ? i - 1 : i);
if ((c == slash) && (prev == slash) && (i > 1))
return normalize(path, n, i - 1);
if ((c == :) && (i > 1))
return normalize(path, n, 0);
prev = c;
}
if (prev == slash)
return normalize(path, n, n - 1);
return path;
}
这里只是简单的处理,复杂的在这里处理
/*
* Normalize the given pathname, whose length is len, starting at the given
* offset; everything before this offset is already normal.
*/
private static String normalize(String path, int len, int off) {
if (len == 0)
return path;
if (off < 3)
off = 0; /* Avoid fencepost cases with UNC pathnames */
int src;
char slash = \\;
StringBuffer sb = new StringBuffer(len);
if (off == 0) {
/* Complete normalization, including prefix */
src = normalizePrefix(path, len, sb);
} else {
/* Partial normalization */
src = off;
sb.append(path.substring(0, off));
}
/*
* Remove redundant slashes from the remainder of the path, forcing all
* slashes into the preferred slash 这里删除n多/
*/
while (src < len) {
char c = path.charAt(src++);
if (isSlash(c)) {
while ((src < len) && isSlash(path.charAt(src)))
src++;
if (src == len) {
/* Check for trailing separator */
int sn = sb.length();
if ((sn == 2) && (sb.charAt(1) == :)) {
/* "z:\\" */
sb.append(slash);
break;
}
if (sn == 0) {
/* "\\" */
sb.append(slash);
break;
}
if ((sn == 1) && (isSlash(sb.charAt(0)))) {
/*
* "\\\\" is not collapsed to "\\" because "\\\\" marks
* the beginning of a UNC pathname. Even though it is
* not, by itself, a valid UNC pathname, we leave it as
* is in order to be consistent with the win32 APIs,
* which treat this case as an invalid UNC pathname
* rather than as an alias for the root directory of the
* current drive.
*/
sb.append(slash);
break;
}
/*
* Path does not denote a root directory, so do not append
* trailing slash
*/
break;
} else {
sb.append(slash);
}
} else {
sb.append(c);
}
}
String rv = sb.toString();
return rv;
}
处理前缀
/*
* A normal Win32 pathname contains no duplicate slashes, except possibly
* for a UNC prefix, and does not end with a slash. It may be the empty
* string. Normalized Win32 pathnames have the convenient property that the
* length of the prefix almost uniquely identifies the type of the path and
* whether it is absolute or relative:
*
* 0 relative to both drive and directory 1 drive-relative (begins with
* \\) 2 absolute UNC (if first char is \\), else directory-relative
* (has form "z:foo") 3 absolute local pathname (begins with "z:\\")
*/
private static int normalizePrefix(String path, int len, StringBuffer sb) {
int src = 0;
while ((src < len) && isSlash(path.charAt(src)))
src++;
char c;
if ((len - src >= 2) && isLetter(c = path.charAt(src))
&& path.charAt(src + 1) == :) {
/*由于java诞生于solaris root的根是/ 这里处理掉前面的/
* Remove leading slashes if followed by drive specifier. This hack
* is necessary to support file URLs containing drive specifiers
* (e.g., "file://c:/path"). As a side effect, "/c:/path" can be
* used as an alternative to "c:/path".
*/
sb.append(c);
sb.append(:);
src += 2;
} else {
src = 0;
if ((len >= 2) && isSlash(path.charAt(0))
&& isSlash(path.charAt(1))) {
/*
* UNC pathname: Retain first slash; leave src pointed at second
* slash so that further slashes will be collapsed into the
* second slash. The result will be a pathname beginning with
* "\\\\" followed (most likely) by a host name.
*/
src = 1;
sb.append(\\);
}
}
return src;
}
其他的几个函数
private static boolean isSlash(char c) {
return (c == \\) || (c == /);
}
private static boolean isLetter(char c) {
return ((c >= a) && (c <= z)) || ((c >= A) && (c <= Z));
}
处理后的
String path = "/D:\\\\apache-tomcat-5.5.23/webapps/ROOT/WEB-INF\\classes/cmd/4_anti_attack_20070625110640_109.xml";
path = normalize(path);
System.out.println(path);
就是windows标准的path