Чи є звичайний спосіб поєднання рядків шляху файлів?


34

Приклад:

var assets = "images/"

var sounds = assets+"sounds/"

Чи звичайніше ставити косу рису на зворотній стороні шляху до файлу?

var assets = "/images"

var sounds = assets+"/sounds"

Чи є інший метод, який є хорошою поширеною практикою?


У Java є статичні строки File.separator та File.pathSeparator, які звучать релевантно. Таким чином ви в безпеці на всіх платформах
Evorlor

1
@Evorlor Ти рідко потребуєш використання, File.separatorхоча Fileі PathAPI приймають і ", /і".
капекс

2
Чи можете ви вказати, якою мовою ви користуєтесь, будь ласка? Напевно, варто додати відповідний тег.
Крістофер Крейціг

@ChristopherCreutzig Я використовую Java - хоча я питав, чи існують якісь загальноприйняті конвенції для поєднання файлових каталогів у рядках. Мабуть, є декілька загальноприйнятих правил, і в них є певний здоровий глузд, але він дещо різниться від мови до мови.
веселий

1
Для чого це варто, у світі Unix (і в URL-адресах) кілька прямих косих середини шляху трактуються однаково до однієї, тому нічого поганого не трапиться, якщо ви помилитесь на стороні більшої косої риски. Це частина Єдиної специфікації Unix; дивіться цю відповідь - unix.stackexchange.com/a/1919/21161
yoniLavi

Відповіді:


37

Майже в кожній з основних мов програмування є бібліотека для обробки роздільників каталогів для вас. Ви повинні використовувати їх. Це спростить ваш код і запобіжить появі помилок .

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

  • На обох кінцях може бути роздільник: "images/"і"/sounds"
  • Тільки в одному є роздільник: "images"і "/sounds"або "images/"і"sounds"
  • Ні має роздільник: "images"і"sounds"

Факт, що кожна частина походить з іншого джерела, означає, що кожне джерело може мати власні уявлення про те, яких конвенцій слід дотримуватися, якби хтось взагалі задумувався над цим! Що б ви не називали, ваш код не повинен турбуватися з цього приводу . Ваш код повинен вирішувати всі випадки, оскільки хтось порушить вашу умову . Це призведе до того, що буде витрачено витрачений час на дослідження причини помилки та виправлення. У мене було кілька неприємних випадків, коли колега зробив припущення про те, як слід форматувати шляхи у файлі конфігурації, тобто я повинен був шукати код і з'ясувати, що вони очікують (або виправити код).

Більшість основних мов надають спосіб зробити це для вас, який уже обробляє багато випадків:

З цим є застереження. Деякі з них припускають, що провідний роздільник каталогів у другому аргументі посилається на кореневий шлях, і це означає, що перший аргумент слід повністю скинути. Я не знаю, чому це вважається корисним; для мене це просто викликає проблеми. Я ніколи не хотів поєднувати дві ділянки шляху і закінчувати тим, що перша частина випадає. Уважно прочитайте документацію для особливих випадків і, якщо необхідно, напишіть обгортку, яка виконує все, що ви хочете, з ними замість їх спеціального поводження.

Це додатково допомагає, якщо у вас є потреба в підтримці різних операційних систем. Ці класи майже всюди пояснюють вибором правильного роздільника. Бібліотеки, як правило, також мають можливість нормалізувати шляхи, щоб відповідати умовам ОС.

У тому випадку, якщо у вашій мові програмування немає доступної бібліотеки, ви повинні написати метод, який обробляє всі ці випадки та використовувати його в ліберальних і в різних проектах.

Це відноситься до категорії "не робіть припущення" та "використовуйте інструменти, які вам допомагають".


2
.NET's Path.Combine не порушена. Просто не годуйте його роздільниками. переконайтеся, що ви прочитали документацію, якщо другий аргумент є кореневим шляхом, він має визначений результат. Вам це може не сподобатися, але це не означає, що він зламаний.
Ерно

4
Переконайтеся, що ви прочитали документацію, щоб переконатися, що вона не намагається бути занадто розумною. Я колись використовував бібліотеку, яка могла б успішно поєднуватися C:\Documents and Settings\Adminіз my folder:document.txtсистемою * nix, щоб створити /home/admin/my folder/document.txt- милий трюк, але в реальному світі евристика передбачала більше помилок, ніж виправлено.
Марк

1
Також для Java Paths.get()просто перетворює сингл Stringв Pathоб'єкт. Щоб приєднатись до шляхів, ви використовуєте Path.resolve()інший Pathабо а String. У Pathкласі є інші методи, які дозволяють додатково поєднувати шляхи різними способами.
Кет

1
Моє погано, здається, я не Pathsдуже добре прочитав документи .
Кет

1
У PowerShell альтернативою методу .NET, [System.IO.Path]::Combine("abc", "\def")який має описане поведінку, є командлет, Join-Path "abc" "\def"який дає "abc\def".
Джеппе Стіг Нільсен

38

У Java відповідь буде "нічим із зазначеного". Найкращою практикою було б збирання імен шляхів за допомогою java.io.Fileкласу; напр

File assets = new File("images");
File sounds = new File(assets, "sounds");

FileКлас також піклується про конкретні платформах імені шляху сепараторів.

Існує окреме питання про те, чи слід ім'я шляху починати з косої риски чи ні. Але це більше стосується коректності, ніж найкращої практики. Ім'я шляху, яке починається з косою рисою, означає щось інше, ніж ім'я шляху, яке немає !!


У ядерній бібліотеці Javascript (ECMA) немає явної підтримки обробки імен, але (принаймні) Node.js забезпечує підтримку через модуль Path.


4
Щось подібне стосується також мов .Net Framework та будь-яких інших, які пропонують класи файлової системи.
Джеймс Снелл

3
Дякую! Це здавалося найбільш корисною відповіддю, хоча бібліотеки повинні існувати для інших мов, зокрема .NET та C ++;
веселий

3
Дійсно, будь-який код, який не використовує бібліотеку, повинен бути відхилений при перегляді коду. За рідкісного випадку, коли бібліотеки не існує, відповідь буде написати самостійно, а не вставляти необроблені рядки.
Gort the Robot

C ++ має Boost :: Filesystem , а C # має System.IO.Path
Mooing Duck

Python має os.path.join. PowerShell має join-path. Я б до цього щось відповів. Я виявив, що якщо вам потрібні шляхи до файлів у декількох фрагментах, це робить ваш код дуже крихким, якщо ви робите припущення, що будь-який з них має шляхи до файлів у певних місцях. Використання цих класів не тільки допомагає при переносимості, але й обробляє всі можливі кромки ребер (косою рисою з обох кінців, косою рисою лише на одній стороні, косою рисою немає взагалі). Ця гнучкість є неоціненною, коли ви скидаєте контури файлів у файл конфігурації.
jpmc26

21

Зауважте, що в .NET ви повинні використовувати метод Path.Combine.

var path = System.IO.Path.Combine("assets", "sounds");

Причиною цього є те, що він «знає» правильні символи, які використовуються при побудові імен папок.

Це знімає «проблему» попереднього чи після виправлення.


4
os.path.join також робить те ж саме для python
StarWeaver

Зверніть увагу , що Path.Combine не отримує вас з бізнесу турбуватися про Seperator: stackoverflow.com/questions/53102 / ...
jmoreno

1
@jmoreno - У моєму прикладі немає роздільників. Питання, з яким ви пов’язані, має жорсткі кодові роздільники, і якщо це принципово неправильно, оскільки другий шлях - абсолютний шлях.
Ерно

Але будьте обережні з цим. Я не впевнений у .NET, але os.path.join('src', '../../../your_secret_stuff') він дійсний у Python; Іншими словами, не слід сліпо використовувати ці методи під час введення користувача.
сапі

@sapi - Звичайно, введення користувачів завжди має бути дезінфіковано, але це відповідальність програміста, а не API.
Ерно

5

Під час побудови контурів я часто використовую функцію, яка додає кінцеву косу рису, якщо її ще немає. Тоді контури можна будувати так:

filename := fs( 'assets') + fs( 'images') + fs( 'icons') + 'some.png';

де fs () додає косу рису, якщо вона потрібна.


5

Папки та файли відрізняються лише одним аспектом: папки закінчуються косою рисою, де файлів немає. Крім того, абсолютні шляхи починаються з а, /де відносних шляхів немає. Якщо ви використовуєте це послідовно поєднуючи шляхи та файли разом, це не буде проблемою.

var absolutepath = "/my/path/";
var relativepath = "css/";
var filename = "test.css";
var relativepathtofilename = "js/test.js";

var a = absolutepath + relativepath + filename; //Output: /my/path/css/test.css
var b = absolutepath + relativepathtofilename;  //Output: /my/path/js/test.js

Об’єднання двох абсолютних шляхів разом не має сенсу, оскільки другий шлях повинен бути відносно першого. Об’єднання двох відносних шляхів разом не є проблемою, але може призвести до невизначеної поведінки, якщо програма не знає, де відносний шлях відносно.


Це, мабуть, найкраще відповіло на моє первісне запитання, я думаю, я краще розумію шляхи до файлів, хоча, як сказали Стівен С та Ерно, мовні бібліотеки - найкраща перша ставка. Це пояснює конвенцію краще. Дякую!
веселий

Шлях або URL-адреси файлової системи?
MrWhite

1
Для всіх намірів і цілей ви можете застосувати це і до урі. Абсолютна урі починалася б з протоколу, але крім того, я думаю, що це було б саме.
Sumurai8

Не впевнений, як працює ваш вихід. Коли я це роблю, я отримую:var a = "/my/path" + "css/" + "test.css"; //Output: "/my/pathcss/test.css"
Деймон

1
@Damon Я змінив редагування. absolutepathмав би закінчитися косою рисою, бо це шлях. Я якось це не помітив, коли писав це.
Sumurai8

4

Я думаю, що немає ніякої магії чи "загальної практики" щодо того, як реалізувати шляхи, але, безумовно, строкове об'єднання - це не шлях. Ви можете розробити власний API для розгляду справ, але це може зажадати певних зусиль. Зокрема, ви повинні бути обережними щодо різних платформ. Наприклад, в Windows \є роздільником, а в системах на базі Unix /- роздільником.

Я не знайомий з бібліотеками Javascript, але я впевнений, що для цих випадків мають бути бібліотеки. Наприклад, у Java, ви можете використовувати API Path, щоб мати справу з операціями незалежного шляху на платформі.


3
Windows насправді підтримує /як роздільник назви файлу шляху. Для цього потрібні примхливості в командному рядку, але API файлів вводу / виводу непогано працюють з косою рисою вперед.
Руслан

en.wikipedia.org/wiki/… "API системи Windows приймає косую рису, і тому всі перераховані вище приклади Unix повинні працювати. Але багато програм у Windows інтерпретують косу рису в інших цілях або трактують її як недійсний символ, і тому вимагають від вас для введення зворотної косої риси - зокрема оболонки cmd.exe (часто її називають "терміналом", оскільки він зазвичай працює у вікні терміналу). "
Mooing Duck

0

Мої особисті переваги:

var assets = "/images"

var sounds = assets+"/sounds"

Я завжди використовую абсолютні шляхи ( /images/...), мені здається, менш схильні до помилок. Це також більш нерозумний доказ, var sounds = assets+"/sounds"тому що навіть якби assetsу вас з'явився кінець косої риски і ви закінчилися /images//sounds, це все одно вирішиться /images/sounds. Одне застереження полягає в тому, що це залежить від вашого обробника запиту. Apache, здається, справляється з цим чудово (принаймні, певні версії / конфігурації, див. Http://www.amazon.com//gp//site-directory//ref=nav_sad ). З іншим способом, який ви закінчили б /imagessounds, не настільки дурний доказ :) Також є можливість перевірити подвійні косої риски та очистити їх. Не варіант з іншим підходом.


11
У всіх моїх контекстах шлях, який починається з косої риски ( /), - це абсолютний шлях, а не відносний шлях. Або ви мали на увазі це лише для розділів шляху, відмінних від першого?
Барт ван Іґен Шенау

@BartvanIngenSchenau Я повністю погоджуюся з вами, і я їм закликаю їх протягом багатьох років, але кожен раз, коли я читаю статтю, написану розробником переднього кінця, вони називають їх відносними шляхами. Я не хотів робити припущення, тож я здогадуюсь, що вибрав меншу з двох зол ...? Тепер, коли я знаю, що у мене є кілька людей, я
оновлю

2
Для веб-розробників /somewhere- це відносний шлях, оскільки він не включає хост, тому браузер шукатиме його на основі хоста поточної сторінки ... У веб-світі http://here/somewhereце абсолютний URI і /somewhereelseвідносно цього. У світі файлової системи /somewhereабсолютна, що йде від кореня /, а "кудись інша" відносно поточного робочого каталогу.
Роб

3
@RobY, rpaskett: Перехід по RFC3986 (RFC, що визначає URI), http://here/somewhereє URI з абсолютним шляхом, /somewhereє відносним посиланням з абсолютним шляхом і somewhere/elseє відносним посиланням на відносний шлях. Мабуть, у цих колах "відносний шлях" використовується для позначення відносної відсилки.
Барт ван Іґен Шенау

1
@BartvanIngenSchenau: у Windows шлях, який починається з косою рисою, є відносним шляхом та відносно CWD. en.wikipedia.org/wiki/…
Mooing Duck

0

У Smalltalk просто визначити / метод у String так, щоб він працював так:

'assets' / 'sounds' => 'assets/sounds'.
'assets/' / 'sounds' => 'assets/sounds'.
'assets' / '/sounds' => 'assets/sounds'.
'assets/' / '/sounds' => 'assets/sounds'.

Ось проста реалізація методу (ви можете покращити його):

/ aString
    | slash first second |
    slash := Directory separator.
    first := self.
    (first endsWith: slash) ifTrue: [first := first allButLast].
    second := aString.
    (second beginsWith: slash) ifTrue: [second := second allButFirst].
    ^first , slash , second

Примітка : Ви також можете приділяти більше уваги до прикордонних справах , таким як '' / '', 'x/' / ''і т.д., для того , щоб визначити правильну поведінку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.