Делает любой знает о любых библиотеках 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)
Пути, которые я канонизирую, не существуют в моей файловой системе, поэтому просто логика метода сделает меня прекрасный, таким образом не требуя никакой синхронизации. Я надеюсь на хорошо протестированную библиотеку вместо того, чтобы иметь необходимость записать мое собственное.
Я думаю, вы можете использовать класс URI для этого; например если путь не содержит символов, которые нужно экранировать в компоненте пути URI, вы можете это сделать.
String normalized = new URI(path).normalize().getPath();
Если путь содержит (или может содержать) символы, которые необходимо экранировать, конструкторы с несколькими аргументами будут экранировать аргумент path
, и вы можете предоставить null
для других аргументов.
Примечания:
Вышеупомянутое нормализует путь к файлу, рассматривая его как относительный URI. Если вы хотите нормализовать весь URI ... включая (необязательную) схему, полномочия и другие компоненты, не вызывайте getPath ()
!
Нормализация URI не требует просмотра файловой системы, как это делает канонизация файлов. Но обратная сторона - то, что нормализация ведет себя иначе, чем каноникализация, когда в пути есть символические ссылки.
Вы можете попробовать такой алгоритм:
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;
}
Он не идеален; он линейен по количеству каталогов, но делает копию в памяти.