Есть ли обычный способ объединить строки пути к файлу?


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 , принимают как /и `\`.
kapex

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

@ChristopherCreutzig Я использую Java - хотя я спрашивал, существуют ли какие-либо обычно используемые соглашения для объединения файловых каталогов в строки. Очевидно, есть несколько общепринятых правил, и в этом есть какой-то здравый смысл, но он немного отличается от языка к языку.
переливающийся

1
Для чего бы это ни стоило, в мире Unix (и в URL) множественные прямые косые черты в середине пути обрабатываются идентично одной, поэтому ничего плохого не произойдет, если вы допустите ошибку на стороне других косых черт. Это часть спецификации Single Unix; см. этот ответ - unix.stackexchange.com/a/1919/21161
yoniLavi

Ответы:


37

Почти каждый основной язык программирования имеет библиотеку для обработки разделителей каталогов для вас. Вы должны использовать их. Это упростит ваш код и предотвратит ошибки .

По моему опыту, обычная причина для объединения строк, как это, заключается в том, что они приходят из разных источников. Иногда это разные части из файла конфигурации. Иногда это константа в сочетании с аргументом функции. В любом случае, когда они поступают из разных источников, вы должны рассмотреть несколько различных возможных случаев использования разделителей на концах:

  • Оба конца могут иметь разделитель: "images/"и"/sounds"
  • Только у одного есть разделитель: "images"и "/sounds"или "images/"и"sounds"
  • Ни один из них не имеет разделителя: "images"и"sounds"

Тот факт, что каждая часть исходит из разных источников, означает, что у каждого источника могут быть свои представления о том, какие соглашения следует соблюдать, если кто-то вообще об этом подумал! Что бы ни вызывало ваш код, вам не нужно об этом беспокоиться . Ваш код должен обрабатывать все случаи, потому что кто- то нарушит ваше соглашение . Это приведет к потере времени на изучение причины ошибки и исправление. У меня было несколько неприятных случаев, когда коллега делал предположение о том, как пути должны быть отформатированы в файле конфигурации, что означало, что я должен был найти код и выяснить, что они ожидали (или исправить код).

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

Есть предостережение с этим. Некоторые из них, по-видимому, предполагают, что ведущий разделитель каталогов во втором аргументе относится к корневому пути и что это означает, что первый аргумент должен быть отброшен полностью. Я не знаю, почему это считается полезным; для меня это просто вызывает проблемы. Я никогда не хотел объединять две части пути и в итоге отбрасывать первую часть. Внимательно прочитайте документацию для особых случаев и, при необходимости, напишите обертку, которая делает с ними то, что вам нужно, а не с их специальной обработкой.

Это также помогает, если у вас есть необходимость поддержки различных операционных систем. Эти классы почти повсеместно объясняют выбор правильного разделителя. В библиотеках также есть способ нормализации путей в соответствии с соглашениями ОС.

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

Это относится к категории «не делайте предположений» и «используйте инструменты, которые вам помогут».


2
.NET 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 core (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 не избавляет вас от забот о разделителе: 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
Для всех намерений и целей, вы можете применить это также к URI. Абсолютный URI будет начинаться с протокола, но, кроме того, я думаю, что это будет то же самое.
Sumurai8

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

1
@ Дэймон Я сделал правку. 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это абсолютное значение, идущее от root /, и «whereelse» относительно текущего рабочего каталога.
Роб

3
@RobY, rpaskett: В соответствии с RFC3986 (RFC, который определяет URI), http://here/somewhereэто URI с абсолютным путем, /somewhereотносительная ссылка с абсолютным путем и somewhere/elseотносительная ссылка с относительным путем. По-видимому, в этих кругах «относительный путь» используется для обозначения относительной ссылки.
Барт ван Инген Шенау

1
@BartvanIngenSchenau: в окнах путь, начинающийся с косой черты, является относительным путем и относительно CWD. en.wikipedia.org/wiki/…
мычанка

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.