Разница между File.separator и косой чертой в путях


200

В чем разница между использованием File.separatorи нормалью /в Java Path-String?

В отличие от двойной обратной косой черты, \\независимость от платформы, похоже, не является причиной, поскольку обе версии работают под Windows и Unix.

public class SlashTest {
    @Test
    public void slash() throws Exception {
        File file = new File("src/trials/SlashTest.java");
        assertThat(file.exists(), is(true));
    }

    @Test
    public void separator() throws Exception {
        File file = new File("src" + File.separator + "trials" + File.separator + "SlashTest.java");
        assertThat(file.exists(), is(true));
    }
}

Перефразируя вопрос, если /работает на Unix и Windows, почему нужно когда-либо использовать File.separator?


5
@Ring «Исторические причины», например, что?
Маркиз Лорн

Ответы:


246

С библиотеками Java для работы с файлами вы можете безопасно использовать /(косую черту, а не обратную косую черту) на всех платформах. Код библиотеки обрабатывает перевод вещей в платформо-зависимые пути внутри страны.

Однако вы можете захотеть использовать его File.separatorв пользовательском интерфейсе, потому что лучше показать людям, что имеет смысл в их ОС, а не что имеет смысл для Java.

Обновление : я не смог за пять минут поиска найти документированное поведение "всегда можно использовать косую черту". Теперь, я уверен, что я видел это задокументированным, но в отсутствие нахождения официальной ссылки (потому что моя память не идеальна), я бы продолжал использовать, File.separatorпотому что вы знаете, что это будет работать.


2
Это также может быть проблемой с производительностью, так как вы ожидаете, что разделитель будет преобразован во что-то другое во время выполнения. Кроме того, не ожидайте, что это произойдет во всех неподдерживаемых JVM.
jpabluz

7
@TJ Crowder: «За пять минут поиска я не смог найти документально подтвержденное поведение« всегда можно использовать косую черту »». Это не особенность JVM, это особенность API Windows NT.
Powerlord

12
@Powerlord: Если Windows это тоже делает, прекрасно - но библиотека (а не JVM) делает то же самое. В частности, Fileиспользуется FileSystem.normalizeповсеместно для «нормализации» путей, полученных через общедоступный API, и почти все, что касается строк пути к файлу (например, FileWriter(String)), используется Fileпод прикрытием.
TJ Crowder

9
С Java7 больше нет необходимости использовать File.separator. Намного проще и понятнее использовать java.nio.file.Paths (Paths.get (first, more ...)) для dir to dir и dir к соединению имени файла.
Волшебник

6
@jpabluz «Проблема с производительностью»! Ты серьезно? Учитывая использование имен файлов на диске, влияние перевода во время выполнения совершенно незначительно. Он должен поддерживаться любой JVM, так как он является частью спецификации File.
Маркиз Лорн

316

Вы используете, File.separatorпотому что когда-нибудь ваша программа может работать на платформе, разработанной в далекой стране, стране странных вещей и незнакомых людей, где лошади плачут, а коровы управляют всеми лифтами. На этой земле люди традиционно используют символ «:» в качестве разделителя файлов, и поэтому JVM покорно подчиняется их желаниям.


4
Да, Пойнти действительно любит нас в Эльбонии (надеюсь, у него нет острой стрижки ;-) (
чудак

4
«... и коровы управляют всеми лифтами». Точно так же я не глотнул кофе, когда читал это. Brilliant.
TJ Crowder

8
В такой стране вы бы использовали новый класс org.apache.chicken.elevators.OperatorUtility, который включает в себя все это безумие для вашего удобства.
Мозг

27

Хотя использование File.separator для ссылки на имя файла является излишним (для тех, кто представляет себе далекие земли, я думаю, что их реализация JVM заменит a /на :аналогично тому, как jvm из окон заменяет его на a \).

Однако иногда вы получаете ссылку на файл, а не создаете его, и вам необходимо проанализировать его, и для того, чтобы сделать это, вам нужно знать разделитель на платформе. File.separator поможет вам сделать это.


11

Хорошо, давайте проверим некоторый код.
File.javaстроки с 428 по 435 в File.<init>:

String p = uri.getPath();
if (p.equals(""))
    throw new IllegalArgumentException("URI path component is empty");

// Okay, now initialize
p = fs.fromURIPath(p);
if (File.separatorChar != '/')
p = p.replace('/', File.separatorChar);

И давайте прочитаем fs/*(FileSystem)*/.fromURIPath()документы:

java.io.FileSystem
public abstract String fromURIPath (String path) Постобработка указанной строки пути
URI, если необходимо. Это используется в win32, например, для преобразования "/ c: / foo" в "c: / foo". Строка пути все еще имеет разделители слэша; код в классе File переведет их после возврата этого метода.

Это означает, FileSystem.fromURIPath()что постобработка по пути URI только в Windows, и потому в следующей строке:

p = p.replace('/', File.separatorChar);

Он заменяет каждый «/» на системно-зависимый seperatorChar, вы всегда можете быть уверены, что «/» безопасен в каждой ОС.


8

Ну, есть больше ОС, чем Unix и Windows (портативные устройства и т. Д.), А Java известна своей переносимостью. Лучше всего использовать его, чтобы JVM могла определить, какая из них лучше для этой ОС.


Большинство из этих ОС используют какой-то вариант UNIX. Старые :разделители в стиле Mac давно исчезли. Кажется, что все, кроме Windows, больше используют стандарт /. И даже окна теперь прекрасно справляются со слешами. Попробуйте cd /windows/systemв системе Windows 10 с основного системного диска. Хотя вы по-прежнему хотите отображать пути с помощью системного разделителя (чтобы не вводить пользователей в заблуждение), вы можете просто использовать косую черту в /любом месте и быть уверенным, что ваш код будет работать везде, где вы, вероятно, будете его развертывать.
Человек-тень

7

Хотя это не имеет большого значения на обратном пути, но на обратном пути.

Конечно, вы можете использовать «/» или «\» в новом файле (путь строки), но File.getPath () даст вам только один из них.


Небольшая коррекция ... В Windows вы можете использовать прямую /или обратную \\ косую черту. Но в любом другом месте лучше использовать косую черту, /иначе у вас будут проблемы.
Человек-тень

6

Поздно на вечеринку. Я на Windows 10 с JDK 1.8 и Eclipse MARS 1.
Я считаю, что

getClass().getClassLoader().getResourceAsStream("path/to/resource");

работает и

getClass().getClassLoader().getResourceAsStream("path"+File.separator+"to"+File.separator+"resource");

не работает и

getClass().getClassLoader().getResourceAsStream("path\to\resource");

не работает. Последние два эквивалентны. Итак ... У меня есть веская причина НЕ использовать File.separator.


6
В этой строке getClass().getClassLoader().getResourceAsStream("path\to\resource");есть табуляция ( \t) и возврат каретки ( \r).
Стефан

9
Это другой сценарий к вопросу. Метод getResourceAsStream класса ClassLoader принимает не путь к файлу, а имя ресурса, которое может или не может быть в файловой системе и задокументировано как принимающее только «/» в качестве разделителя пути ресурса.
daiscog

@ Стефану нет ничего смешного, потому File.separatorчто это обратный слеш. Это только в жестко запрограммированных строках, где он рассматривается как экранирующий символ, где вам нужно экранировать обратную косую черту. Если вы сохранили символ в текстовом файле, или в charили, Stringто вам не нужно экранировать его во второй раз, поскольку он уже был преобразован в ожидаемый символ обратной косой черты. Попробуйте сами, чтобы увидеть:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Человек-тень

2
@ Стефан, я вижу ... Ты говорил о третьей линии. Ты прав. В этой строке (жестко запрограммированная строка) вам нужно будет экранировать escape-символ. Мои глаза остановились на 2-й строке, и я даже не заметил 3-ю строку вначале.
Shadow Man

3

Портативность просто и понятно.


Да, для переносимости, не используйте обратную косую черту. Используйте косую черту /или системный разделитель File.separator. Оба из них, кажется, работают везде. Хотя File.separatorгарантированно работает везде, простой слэш /также, кажется, работает везде. Если это не сработает где-то, то я бы хотел услышать об этом. Я считаю, что это будет работать на всех системах. По крайней мере, я еще не нашел нигде, где бы /это не работало (Mac OSX, Windows, * nix, Android, iOS - я не проверял Mac до OSX, которые использовали «:» в качестве разделителя, OS / 2, NeXT или любая другая действительно древняя ОС).
Shadow Man

1

«Java SE8 для программистов» утверждает, что Java справится с любым из них. (стр. 480, последний абзац). В примере утверждается, что:

c:\Program Files\Java\jdk1.6.0_11\demo/jfc

разберутся просто отлично. Обратите внимание на последний разделитель (в стиле Unix).

Это липко и, вероятно, подвержено ошибкам, но это то, что они (Deitel и Deitel) утверждают.

Я думаю, что путаница для людей, а не Java, является достаточной причиной, чтобы не использовать эту (неправильную?) Функцию.


1

Как господа описали разницу с деталями варианта.

Я хотел бы рекомендовать использовать Apache Commons io api, класс FilenameUtilsпри работе с файлами в программе с возможностью развертывания на нескольких ОС.


0

Путь к файлу или каталогу указывается с использованием соглашений об именах хост-системы. Однако класс File определяет зависящие от платформы константы, которые можно использовать для обработки имен файлов и каталогов независимо от платформы.

Files.seperator определяет символ или строку, которые разделяют каталог и компоненты файла в имени пути. Этот разделитель - '/', '\' или ':' для Unix, Windows и Macintosh соответственно.


":" Для Macintosh является древним. Начиная с OSX, Mac также использует «/» (косая черта), так как он работает в форме UNIX со стандартной файловой системой UNIX под капотом.
Shadow Man


0

Использование File.separator заставило Ubuntu генерировать файлы с «\» в имени вместо каталогов. Может быть, мне лень, как я делаю файлы (и каталоги), и я мог бы избежать этого, независимо от того, что каждый раз использую «/», чтобы избежать файлов с «\» в названии.


0

Что вы должны сделать, если вы пытаетесь создать файл по какому-либо готовому пути (сохраненному в базе данных, например), используя разделитель Linux?

Может быть, просто используйте путь для создания файла:

new File("/shared/folder/file.jpg");

Но Windows использует другой разделитель ( \). Итак, является ли альтернативой преобразование разделителя слеша в платформу независимым? Подобно:

new File(convertPathToPlatformIndependent("/shared/folder"));

Этот метод, convertPathToPlatformIndependentвероятно, будет иметь какое-то разделение на "/" и объединиться с File.separator.

Ну, для меня это нехорошо для языка, который не зависит от платформы (верно?), А Java уже поддерживает использование в /Windows или Linux. Но если вы работаете с путями и вам нужно каждый раз вспоминать об этом преобразовании, это будет кошмаром, и вы не получите никакой реальной выгоды для приложения в будущем (возможно, во вселенной, описанной @Pointy).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.