Разница между 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.