是否有人知道我可以用来生成规范路径的任何Java库(基本上删除了反向引用)。
我需要做以下事情:
原始路径 - >规范路径
/../foo/ -> /foo
/foo/ -> /foo
/../../../ -> /
/./foo/./ -> /foo
//foo//bar -> /foo/bar
//foo/../bar -> /bar
等...
目前我懒洋洋地依赖使用:
new File("/", path).getCanonicalPath();
但这解决了针对实际文件系统的路径,并且已同步。
java.lang.Thread.State: BLOCKED (on object monitor)
at java.io.ExpiringCache.get(ExpiringCache.java:55)
- waiting to lock <0x93a0d180> (a java.io.ExpiringCache)
at java.io.UnixFileSystem.canonicalize(UnixFileSystem.java:137)
at java.io.File.getCanonicalPath(File.java:559)
我的规范化路径在我的文件系统中不存在,因此只需该方法的逻辑就可以了,因此不需要任何同步。我希望有一个经过良好测试的库,而不是自己编写。
答案 0 :(得分:21)
我认为您可以使用URI类来执行此操作;例如如果路径中不包含需要在URI路径组件中转义的字符,则可以执行此操作。
String normalized = new URI(path).normalize().getPath();
如果路径包含(或可能包含)需要转义的字符,则多参数构造函数将转义path
参数,并且可以为其他参数提供null
。
注意:
上面通过将文件路径视为相对URI来规范化文件路径。如果要标准化整个URI ...包括(可选)方案,权限和其他组件,请不要调用getPath()
!
URI规范化不涉及像文件规范化那样查看文件系统。但另一方面,当路径中存在符号链接时,规范化与规范化的行为不同。
答案 1 :(得分:17)
使用 Apache Commons IO (一个着名且经过良好测试的库)
public static String normalize(String filename)
将完全满足您的需求。
示例:
String result = FilenameUtils.normalize(myFile.getAbsolutePath());
答案 2 :(得分:11)
如果您不需要路径规范化而只需要规范化,那么在Java 7中您可以使用java.nio.file.Path.normalize
方法。
根据{{3}}:
此方法不访问文件系统;路径可能找不到存在的文件。
如果使用File对象,可以使用以下内容:
file.toPath().normalize().toFile()
答案 3 :(得分:4)
您可以尝试这样的算法:
String collapsePath(String path) {
/* Split into directory parts */
String[] directories = path.split("/");
String[] newDirectories = new String[directories.length];
int i, j = 0;
for (i=0; i<directories.length; i++) {
/* Ignore the previous directory if it is a double dot */
if (directories[i].equals("..") && j > 0)
newDirectories[j--] = "";
/* Completely ignore single dots */
else if (! directories[i].equals("."))
newDirectories[j++] = directories[i];
}
/* Ah, what I would give for String.join() */
String newPath = new String();
for (i=0; i < j; i++)
newPath = newPath + "/" + newDirectories[i];
return newPath;
}
不完美;它在目录数量上是线性的,但确实在内存中复制。
答案 4 :(得分:0)
哪种路径被认定为规范路径取决于操作系统。 这就是Java需要在文件系统上检查它的原因。 因此,在不知道操作系统的情况下测试路径没有简单的逻辑。
答案 5 :(得分:0)
因此,尽管规范化可以解决问题,但是此过程公开了比简单调用Paths.normalize()
说我想找到一个不在文件系统当前目录中的文件。 我的工作代码文件是
myproject/src/JavaCode.java
位于myproject / src /中。我的文件位于
../../data/myfile.txt
我正在测试从JavaCode.java运行我的代码的程序
public static void main(String[] args) {
findFile("../../data","myfile.txt");
System.out.println("Found it.");
}
public static File findFile(String inputPath, String inputFile) {
File dataDir = new File("").getAbsoluteFile(); // points dataDir to working directory
String delimiters = "" + '\\' + '/'; // dealing with different system separators
StringTokenizer st = new StringTokenizer(inputPath, delimiters);
while(st.hasMoreTokens()) {
String s = st.nextToken();
if(s.trim().isEmpty() || s.equals("."))
continue;
else if(s.equals(".."))
dataDir = dataDir.getParentFile();
else {
dataDir = new File(dataDir, s);
if(!dataDir.exists())
throw new RuntimeException("Data folder does not exist.");
}
}
return new File(dataDir, inputFile);
}
已将文件放置在指定位置,应打印“找到它”。
答案 6 :(得分:-1)
我假设你有字符串,你想要字符串,你现在可以使用Java 7,而你的默认文件系统使用'/'作为路径分隔符,所以试试:
String output = FileSystems.getDefault().getPath(input).normalize().toString();
您可以尝试使用:
/**
* Input Output
* /../foo/ -> /foo
* /foo/ -> /foo
* /../../../ -> /
* /./foo/./ -> /foo
* //foo//bar -> /foo/bar
* //foo/../bar -> /bar
*/
@Test
public void testNormalizedPath() throws URISyntaxException, IOException {
String[] in = new String[]{"/../foo/", "/foo/", "/../../../", "/./foo/./",
"//foo/bar", "//foo/../bar", "/", "/foo"};
String[] ex = new String[]{"/foo", "/foo", "/", "/foo", "/foo/bar", "/bar", "/", "/foo"};
FileSystem fs = FileSystems.getDefault();
for (int i = 0; i < in.length; i++) {
assertEquals(ex[i], fs.getPath(in[i]).normalize().toString());
}
}