Czy istnieje konwencjonalny sposób łączenia ciągów ścieżek plików?

34

W przykładzie:

var assets = "images/"

var sounds = assets+"sounds/"

Czy bardziej konwencjonalne jest umieszczanie ukośnika z tyłu ścieżki do pliku?

var assets = "/images"

var sounds = assets+"/sounds"

Czy istnieje inna metoda, która jest dobrą powszechną praktyką?

jairidescent
źródło
Java ma statyczne ciągi File.separator i File.pathSeparator, które wydają się odpowiednie. W ten sposób jesteś bezpieczny na wszystkich platformach
Evorlor
1
@Evorlor Rzadko trzeba jednak używać File.separator, Filea Pathinterfejsy API i akceptują zarówno, jak /i `\`.
kapex
2
Czy mógłbyś wskazać używany język? Prawdopodobnie warto dodać odpowiedni tag.
Christopher Creutzig
@ChristopherCreutzig Korzystam z Javy - chociaż pytałem, czy istnieją jakieś powszechnie stosowane konwencje łączenia katalogów plików w ciągi znaków. Najwyraźniej istnieje kilka ogólnie przyjętych zasad i wiąże się z nimi zdrowy rozsądek, ale różni się ona w zależności od języka.
iiridescent
1
Jeśli chodzi o to, co jest warte, w świecie uniksowym (i w adresach URL) wiele ukośników w przód na ścieżce jest traktowanych identycznie jak jeden, więc nic złego się nie stanie, jeśli popełnisz błąd po stronie więcej ukośników. Jest to część specyfikacji Single Unix; zobacz tę odpowiedź - unix.stackexchange.com/a/1919/21161
yoniLavi

Odpowiedzi:

37

Prawie każdy główny język programowania ma bibliotekę do obsługi separatorów katalogów. Powinieneś je wykorzystać. Uprości to Twój kod i zapobiegnie błędom .

Z mojego doświadczenia wynika, że ​​typowym powodem łączenia takich ciągów jest to, że pochodzą one z różnych źródeł. Czasami różni się od pliku konfiguracyjnego. Czasami jest to ciągłe łączenie z argumentem funkcji. We wszystkich przypadkach, gdy pochodzą one z różnych źródeł, należy rozważyć kilka różnych możliwych przypadków dotyczących separatorów na końcach, które należy połączyć:

  • Oba końce mogą mieć separator: "images/"i"/sounds"
  • Tylko jeden ma separator: "images"i "/sounds"lub "images/"i"sounds"
  • Żaden nie ma separatora: "images"i"sounds"

Fakt, że każda część pochodzi z innego źródła, oznacza, że ​​każde źródło może mieć własne wyobrażenia o konwencjach, których należy przestrzegać, jeśli ktoś w ogóle o tym pomyśli! Cokolwiek wywołuje Twój kod, nie powinno się o to martwić . Twój kod powinien obsłużyć wszystkie sprawy, ponieważ ktoś naruszy twoją konwencję . Spowoduje to, że stracisz czas na zbadanie przyczyny błędu i naprawę. Miałem kilka nieprzyjemnych okazji, w których współpracownik zakładał, jak należy sformatować ścieżki w pliku konfiguracyjnym, co oznacza, że ​​musiałem poszukać kodu i dowiedzieć się, czego się spodziewali (lub naprawić kod).

Większość głównych języków udostępnia dla ciebie metodę, która już obsługuje wiele przypadków:

Jest z nimi zastrzeżenie. Wiele z nich wydaje się zakładać, że wiodący separator katalogu w drugim argumencie odnosi się do ścieżki katalogu głównego i że oznacza to, że pierwszy argument powinien zostać całkowicie usunięty. Nie wiem, dlaczego uważa się to za przydatne; dla mnie to po prostu powoduje problemy. Nigdy nie chciałem łączyć dwóch części ścieżki i kończyć zrzucaniem pierwszej części. Przeczytaj uważnie dokumentację dotyczącą specjalnych przypadków, a jeśli to konieczne, napisz opakowanie, które robi to, co chcesz, zamiast ich specjalnej obsługi.

Pomaga to dodatkowo, jeśli potrzebujesz obsługi różnych systemów operacyjnych. Klasy te niemal powszechnie uwzględniają wybór właściwego separatora. Biblioteki zwykle mają sposób na znormalizowanie ścieżek, aby pasowały również do konwencji systemu operacyjnego.

W przypadku, gdy Twój język programowania nie ma łatwo dostępnej biblioteki, powinieneś napisać metodę, która obsługuje wszystkie te przypadki i używać jej swobodnie w różnych projektach.

Należy to do kategorii „nie rób założeń” i „używaj narzędzi, które ci pomogą”.

jpmc26
źródło
2
Path.Combine .NET nie jest uszkodzony. Po prostu nie podawaj separatorów. upewnij się, że czytasz dokumentację, jeśli drugi argument jest ścieżką katalogu głównego, ma określony wynik. Może ci się nie podobać, ale to nie znaczy, że jest zepsuty.
Erno,
4
Przeczytaj dokumentację, aby upewnić się, że nie jest zbyt sprytna. Kiedyś korzystałem z biblioteki, którą można z powodzeniem łączyć C:\Documents and Settings\Adminz my folder:document.txtsystemem * nix do produkcji /home/admin/my folder/document.txt- urocza sztuczka, ale w prawdziwym świecie heurystyka spowodowała więcej błędów niż naprawiła.
Mark
1
Ponadto w przypadku języka Java Paths.get()po prostu przekształca pojedynczy obiekt Stringw Pathobiekt. Do łączenia ścieżek użyjesz Path.resolve()innej, Pathlub innej String. W Pathklasie znajdują się inne metody, które pozwalają na łączenie ścieżek na różne sposoby.
Kat
1
Mój zły, wygląda na to, że nie czytałem Pathszbyt dobrze dokumentów .
Kat
1
W programie PowerShell alternatywą dla metody .NET, [System.IO.Path]::Combine("abc", "\def")która ma opisane zachowanie, jest cmdlet, Join-Path "abc" "\def"który daje "abc\def".
Jeppe Stig Nielsen
38

W Javie odpowiedzią byłoby „żadne z powyższych”. Najlepszą praktyką byłoby gromadzenie nazw ścieżek za pomocą java.io.Fileklasy; na przykład

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

FileKlasa dba również platformy specyficzne separatorów ścieżki dostępu.

Istnieje osobna kwestia, czy nazwa ścieżki powinna zaczynać się od ukośnika, czy nie. Ale to bardziej dotyczy poprawności niż najlepszych praktyk. Nazwa ścieżki zaczynająca się od ukośnika oznacza coś innego niż nazwa ścieżki, która nie !!


Nie ma wyraźnego wsparcia dla obsługi nazw ścieżek w podstawowej bibliotece JavaScript (ECMA), ale (przynajmniej) Node.js zapewnia wsparcie poprzez moduł Path.

Stephen C.
źródło
4
Podobnie jest w przypadku języków .Net Framework i wszystkich innych, które oferują klasy systemów plików.
James Snell
3
Dziękuję Ci! Wydawało się, że jest to najbardziej pomocna odpowiedź, mimo że dla konkretnych języków powinny istnieć biblioteki dla innych języków, takich jak .NET i C ++;
iiridescent
3
Naprawdę każdy kod, który nie korzysta z biblioteki, powinien zostać odrzucony podczas przeglądania kodu. W rzadkich przypadkach, gdy nie ma biblioteki, odpowiedzią byłoby napisanie jej samodzielnie, a nie wklejenie surowych ciągów.
Gort the Robot
C ++ ma Boost :: Filesystem , a C # ma System.IO.Path
Mooing Duck
Python ma os.path.join. PowerShell ma join-path. Dodałbym coś do tej odpowiedzi. Odkryłem, że jeśli potrzebujesz ścieżek plików w wielu częściach, to sprawia, że ​​twój kod jest bardzo delikatny, jeśli przyjmujesz założenia, że ​​któreś z nich ma ścieżki plików w określonych miejscach. Korzystanie z tych klas nie tylko pomaga w przenoszeniu, ale także obsługuje wszystkie możliwe przypadki krawędzi (cięcie na obu końcach do połączenia, cięcie tylko na jednej stronie, bez żadnego cięcia między nimi). Ta elastyczność jest nieoceniona, gdy upuszczasz ścieżki do pliku konfiguracyjnego.
jpmc26
21

Zauważ, że w .NET powinieneś użyć metody Path.Combine.

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

Powodem tego jest to, że „zna” prawidłowe znaki, które mają być użyte podczas konstruowania nazw folderów.

Eliminuje to „problem” wstępnego lub końcowego naprawiania.

Eee nie
źródło
4
os.path.join robi w zasadzie to samo dla Pythona
StarWeaver
Zauważ, że path.combine nie wyciąga cię z martwienia się o separator: stackoverflow.com/questions/53102/…
jmoreno
1
@jmoreno - W moim przykładzie nie ma żadnych separatorów. Pytanie, z którym się łączysz, ma zakodowane na stałe separatory i jest zasadniczo błędne, ponieważ druga ścieżka jest ścieżką absolutną.
Erno,
Uważaj jednak na to. Nie jestem pewien co do .NET, ale os.path.join('src', '../../../your_secret_stuff') jest poprawny w Pythonie; innymi słowy, nie używaj tych metod na ślepo na dane wprowadzone przez użytkownika.
sapi
@sapi - Oczywiście, wkład użytkownika powinien być zawsze odkażony, ale to jest odpowiedzialność programisty, a nie API.
Erno,
5

Podczas budowania ścieżek często używam funkcji, która dodaje ukośnik, jeśli jeszcze go nie ma. Następnie można zbudować ścieżki:

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

gdzie fs () dodaje ukośnik końcowy, jeśli jest potrzebny.

Grandmaster B.
źródło
5

Foldery i pliki różnią się tylko jednym aspektem: foldery kończą się ukośnikiem, a pliki nie. Ponadto ścieżki bezwzględne rozpoczynają się od /ścieżek względnych, w których nie. Jeśli użyjesz tego konsekwentnie łącząc ścieżki i pliki razem, nie powinno to stanowić problemu.

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

Łączenie dwóch absolutnych ścieżek razem nie ma sensu, ponieważ druga ścieżka powinna być względna do pierwszej ścieżki. Łączenie dwóch ścieżek względnych razem nie stanowi problemu, ale może prowadzić do nieokreślonego zachowania, jeśli program nie wie, gdzie ścieżka względna jest względna.

Sumurai8
źródło
Prawdopodobnie najlepiej to odpowiadało na moje pierwotne pytanie, myślę, że lepiej rozumiem ścieżki plików, chociaż, jak powiedzieli Stephen C i Erno, biblioteki językowe są najlepszym wyborem. To jednak lepiej tłumaczy konwencję. Dziękuję Ci!
iiridescent
Ścieżki do systemu plików lub adresy URL?
MrWhite
1
Do wszystkich celów i celów możesz to również zastosować w przypadku identyfikatorów URI. Absolutne URI zaczynałoby się od protokołu, ale poza tym myślę, że to samo.
Sumurai8
Nie jestem pewien, jak działa Twój wydruk. Kiedy to robię, otrzymuję:var a = "/my/path" + "css/" + "test.css"; //Output: "/my/pathcss/test.css"
Damon,
1
@Damon Dokonałem edycji. absolutepathpowinien zakończyć się ukośnikiem, ponieważ jest to ścieżka. Jakoś przeoczyłem to, kiedy to napisałem.
Sumurai8
4

Myślę, że nie ma magii ani „powszechnej praktyki” w zakresie wdrażania ścieżek, ale z pewnością łączenie łańcuchów nie jest właściwą drogą. Możesz opracować własny interfejs API do obsługi spraw, ale może to wymagać pewnego wysiłku. W szczególności należy zachować ostrożność w przypadku różnych platform. Na przykład w Windows \jest separatorem, podczas gdy w systemach uniksowych /jest separatorem.

Nie znam bibliotek Javascript, ale jestem pewien, że powinny istnieć biblioteki do obsługi tych przypadków. Na przykład w Javie można użyć interfejsu API ścieżki do obsługi niezależnych od platformy operacji na ścieżkach.

Wickoo
źródło
3
System Windows faktycznie obsługuje /ogranicznik nazw plików. To wymaga dziwactwa w wierszu poleceń, ale interfejsy API we / wy plików działają dobrze z ukośnikiem do przodu.
Ruslan
en.wikipedia.org/wiki/... "interfejs API systemu Windows akceptuje slash, dlatego wszystkie powyższe przykłady Uniksa powinny działać. Ale wiele aplikacji w Windows interpretuje slash do innych celów lub traktuje go jako nieprawidłowy znak, a zatem wymaga Ciebie aby wprowadzić ukośnik odwrotny - zwłaszcza powłokę cmd.exe (często nazywaną „terminalem”, ponieważ zwykle działa w oknie terminala). ”
Mooing Duck
0

Moje osobiste preferencje są następujące:

var assets = "/images"

var sounds = assets+"/sounds"

Zawsze używam ścieżek bezwzględnych ( /images/...), dla mnie jest to mniej podatne na błędy. Jest to również bardziej głupi dowód na użycie, var sounds = assets+"/sounds"ponieważ nawet jeśli assetsmiałbyś końcowy ukośnik i skończyłbyś z /images//soundsnim, nadal by to rozwiązał /images/sounds. Jedynym zastrzeżeniem jest to, że zależy to od obsługi żądania. Wydaje się, że Apache dobrze sobie z tym radzi (przynajmniej niektóre wersje / konfiguracje, patrz http://www.amazon.com//gp//site-directory//ref=nav_sad ). W inny sposób, w jaki byś skończył /imagessounds, nie tak głupi dowód :) Istnieje również możliwość sprawdzenia podwójnych ukośników i ich wyczyszczenia. W przypadku drugiego podejścia nie ma takiej opcji.

rpaskett
źródło
11
We wszystkich kontekstach, które znam, ścieżka rozpoczynająca się od ukośnika ( /) jest ścieżką bezwzględną , a nie ścieżką względną. Czy miałeś na myśli to tylko dla odcinków ścieżki innych niż pierwszy?
Bart van Ingen Schenau
@BartvanIngenSchenau Całkowicie się z tobą zgadzam i nazywam ich od lat, ale za każdym razem, gdy czytam artykuł napisany przez programistę front-end, nazywają je względnymi ścieżkami. Nie chciałem zakładać, więc chyba wybrałem mniejsze zło ...? Teraz, gdy wiem, że mam kilku ludzi po swojej stronie, zaktualizuję swoją odpowiedź :)
rpaskett
2
Dla twórców stron internetowych /somewherejest to ścieżka względna, ponieważ nie zawiera hosta, więc przeglądarka będzie ją wyszukiwać na podstawie hosta bieżącej strony ... W świecie internetowym http://here/somewherejest bezwzględnym identyfikatorem URI i /somewhereelsejest z nim związany. W świecie systemów plików /somewherejest absolutny, pochodzi z katalogu głównego /, a „gdzieś” odnosi się do bieżącego katalogu roboczego.
Rob
3
@RobY, rpaskett: Going by RFC3986 (RFC, który definiuje identyfikatory URI), http://here/somewherejest identyfikatorem URI ze ścieżką bezwzględną, /somewherejest referencją względną ze ścieżką bezwzględną i somewhere/elsereferencją względną ze ścieżką względną. Najwyraźniej w tych kręgach „ścieżka względna” jest używana w odniesieniu do odniesienia względnego.
Bart van Ingen Schenau
1
@BartvanIngenSchenau: w systemie Windows ścieżka rozpoczynająca się od ukośnika jest ścieżką względną i odnosi się do CWD. en.wikipedia.org/wiki/…
Kaczka Mooing
0

W Smalltalk łatwo jest zdefiniować metodę / w String, aby działała w następujący sposób:

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

Oto prosta implementacja metody (możesz ją ulepszyć):

/ 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

Uwaga : możesz również zapłacić większą uwagę na przypadki graniczne, takie jak '' / '', 'x/' / ''itd, w celu określenia właściwego zachowania.

Leandro Caniglia
źródło