Різниця між 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
@Рінг "Історичні причини", наприклад, що?
Маркіз Лорн

Відповіді:


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 (перший, докладніше ...)) для dir to dir та dir to filename join.
magiccrafter

6
@jpabluz "Проблема з продуктивністю"! Ти серйозно? Зважаючи на те, що назви файлів розміщуються на диску, вплив перекладу на час виконання перекладу є абсолютно незначним. Він повинен підтримуватися будь-яким JVM, оскільки він є частиною специфікації File.
Маркіз Лорн

316

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


4
Так, Pointy насправді занадто сильно стригає нас в ельбонії (сподіваюсь, що у нього немає чіткої стрижки ;-) (
витівка

4
"... і корови експлуатують усі ліфти". Так само добре, що я не пив ковтка кави, коли читав це. Блискуча.
TJ Crowder

8
У такій країні ви б скористалися новим класом org.apache.chicken.elevators.OperatorUtility, який втілює всю цю божевільність для вашої зручності.
Мозок

27

Хоча використання File.separator для посилання на ім'я файлу є надмірним (для тих, хто уявляє собі далекі землі, я думаю, що їх реалізація JVM замінить на /такий :же, як Windows 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
публічний конспект 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 з основного системного диска. Хоча ви все ще хочете відображати шляхи за допомогою системного роздільника (щоб не бентежити своїх користувачів), ви можете просто використовувати нахильну косу рису в /будь-якому іншому місці та бути впевненим, що ваш код буде працювати де завгодно, якщо ви, ймовірно, його розгорніть.
Shadow Man

7

Хоча це не має великої різниці в дорозі, але на зворотному шляху.

Звичайно, ви можете використовувати або "/" або "\" у новому файлі (String path), але File.getPath () надасть вам лише один із них.


Невелика корекція ... У Windows ви можете використовувати нахил вперед /або назад \\ . Але в будь-якому іншому місці вам краще скористатися пересічкою вперед /або у вас виникнуть проблеми.
Shadow Man

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 не приймає шлях до файлу, але ім'я ресурсу, яке може бути, а може і не бути у файловій системі, і задокументоване так, що лише приймає '/' як роздільник шляху ресурсу.
дайског

@Stephan там немає смішного втечі, оскільки File.separatorце зворотний кут . Це лише у жорстко зашифрованих рядках, де це трактується як символ втечі, де вам потрібно уникнути нахилу. Якщо ви зберегли символ у текстовому файлі, або в а charабо Stringтоді, вам не потрібно уникати його вдруге, оскільки він уже перетворений на очікуваний символ зворотної косої риси. Спробуйте це переконатися:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man

2
@Stephan о, я бачу ... Ви говорили про 3-й рядок. Ви праві. У цьому рядку (жорстко закодований рядок) вам потрібно буде уникнути символу втечі. Мої очі зупинилися на другому рядку, і я навіть спочатку не помітив 3-го рядка.
Shadow Man

3

портативність звичайна і проста.


Так, для переносимості не використовуйте зворотну косу рису. Використовуйте косою рискою вперед /або системним роздільником File.separator. Вони, здається, працюють скрізь. Незважаючи на те File.separator, що гарантовано працює скрізь, простий косий рядок /також працює скрізь. Якщо це десь не працює, я хотів би почути про це. Я вірю, що це буде працювати у всіх системах. Принаймні, я ще не міг знайти місця, де /це не працює (Mac OSX, Windows, * nix, Android, iOS - я не перевіряв попередньо Mac OS, які використовували ":" як роздільник, хоча 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 відповідно.


Значення ":" для Макінтоша давнє. Оскільки 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.