Esiste un modo convenzionale per combinare le stringhe del percorso del file?


34

In un esempio:

var assets = "images/"

var sounds = assets+"sounds/"

È più convenzionale inserire la barra sul retro di un percorso di file?

var assets = "/images"

var sounds = assets+"/sounds"

Esiste un altro metodo che è una buona pratica comune?


Java ha le stringhe statiche File.separator e File.pathSeparator che sembrano rilevanti. In questo modo sei al sicuro su tutte le piattaforme
Evorlor

1
@Evorlor Tuttavia, raramente è necessario utilizzare File.separator, le API Filee Pathaccettano entrambi /e `\`.
Kapex

2
Potresti indicare quale lingua stai usando, per favore? Probabilmente vale la pena aggiungere il tag corrispondente.
Christopher Creutzig,

@ChristopherCreutzig Sto usando Java, anche se chiedevo se ci fossero convenzioni comunemente usate per combinare le directory dei file nelle stringhe. Apparentemente ci sono alcune regole generalmente accettate e un certo buon senso è coinvolto, ma varia un po 'da una lingua all'altra.
iiridescente,

1
Per quello che vale, nel mondo unix (e negli URL), più barre in avanti nel mezzo di un percorso vengono trattate in modo identico a una singola, quindi non accadrebbe nulla di brutto se si sbagliasse sul lato di più barre. Fa parte della specifica Unix singola; vedi questa risposta - unix.stackexchange.com/a/1919/21161
yoniLavi

Risposte:


37

Quasi tutti i principali linguaggi di programmazione hanno una libreria per gestire i separatori di directory per te. Dovresti sfruttarli. Ciò semplifica il tuo codice e previene i bug .

Nella mia esperienza, la solita ragione per combinare stringhe come questa è che provengono da fonti diverse. A volte sono pezzi diversi da un file di configurazione. A volte è una costante combinazione con un argomento di funzione. In ogni caso, quando provengono da fonti diverse, è necessario considerare diversi casi possibili riguardanti i separatori alle estremità da combinare:

  • Entrambe le estremità potrebbero avere un separatore: "images/"e"/sounds"
  • Solo uno ha un separatore: "images"e "/sounds"o "images/"e"sounds"
  • Nessuno dei due ha un separatore: "images"e"sounds"

Il fatto che ogni parte provenga da una fonte diversa significa che ogni fonte potrebbe avere le sue idee su quali convenzioni seguire, se qualcuno ci pensasse su! Qualunque cosa stia chiamando il tuo codice non dovrebbe preoccuparti di questo . Il tuo codice dovrebbe gestire tutti i casi perché qualcuno violerà la tua convenzione . Ciò comporterà uno spreco di tempo per indagare sulla causa di un errore e apportare una correzione. Ho avuto diverse spiacevoli occasioni in cui un collega ha fatto un'ipotesi su come i percorsi dovrebbero essere formattati in un file di configurazione, il che significa che ho dovuto andare a cercare il codice e capire cosa si aspettavano (o correggere il codice).

La maggior parte delle lingue principali fornisce un metodo per farlo che gestisce già molti dei casi:

C'è un avvertimento con questi. Alcuni di questi sembrano supporre che un separatore di directory principale nel secondo argomento si riferisca a un percorso di root e che ciò significhi che il primo argomento deve essere eliminato completamente. Non so perché questo sia considerato utile; per me, causa solo problemi. Non ho mai voluto combinare due parti del percorso e finire con la prima parte che viene abbandonata. Leggi attentamente la documentazione per casi speciali e, se necessario, scrivi un wrapper che fa quello che vuoi con questi invece della loro gestione speciale.

Questo aiuta ulteriormente se hai bisogno di supportare diversi sistemi operativi. Queste classi spiegano quasi ovunque la scelta del separatore corretto. Le librerie di solito hanno anche un modo di normalizzare i percorsi per adattarsi alle convenzioni del sistema operativo.

Nel caso in cui il tuo linguaggio di programmazione non abbia una libreria prontamente disponibile, dovresti scrivere un metodo che gestisca tutti questi casi e lo usi liberamente e in tutti i progetti.

Questo rientra nella categoria "non fare ipotesi" e "usa strumenti che ti aiutano".


2
Path.Combine di .NET non è rotto. Basta non dargli da mangiare separatori. assicurati di leggere la documentazione, se il secondo argomento è un percorso radice ha un risultato definito. Potrebbe non piacerti, ma ciò non significa che sia rotto.
Erno,

4
Assicurati di leggere la documentazione per assicurarti che non stia cercando di essere troppo intelligente. Una volta ho usato una libreria che poteva combinarsi C:\Documents and Settings\Admincon successo con my folder:document.txtun sistema * nix per produrre /home/admin/my folder/document.txt- un trucco carino, ma nel mondo reale, l'euristica coinvolta ha introdotto più bug di quanti ne abbiano risolti.
Segna il

1
Inoltre, per Java, Paths.get()converte solo un singolo Stringin un Pathoggetto. Per unire i percorsi, devi usare Path.resolve(), che può contenere un altro Patho un String. Ci sono altri metodi nella Pathclasse che consentono ulteriormente di unire percorsi in vari modi.
Kat,

1
Mio male, sembra che non abbia letto Pathsmolto bene i documenti .
Kat

1
In PowerShell, un'alternativa al metodo .NET [System.IO.Path]::Combine("abc", "\def")che presenta il comportamento descritto, è il cmdlet Join-Path "abc" "\def"che fornisce "abc\def".
Jeppe Stig Nielsen

38

In Java, la risposta sarebbe "nessuna delle precedenti". La migliore pratica sarebbe quella di assemblare i percorsi usando la java.io.Fileclasse; per esempio

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

La Fileclasse si occupa anche dei separatori di percorsi specifici della piattaforma.

C'è un problema a parte se il tuo percorso deve iniziare con una barra o meno. Ma ciò ha più a che fare con la correttezza che con le migliori pratiche. Un percorso che inizia con una barra significa qualcosa di diverso da un percorso che non lo fa !!


Non esiste un supporto esplicito per la gestione dei percorsi nella libreria Javascript (ECMA) principale, ma (almeno) Node.js fornisce supporto tramite il modulo Path.


4
Qualcosa di simile vale anche per i linguaggi .Net Framework e tutti gli altri che offrono classi di filesystem.
James Snell,

3
Grazie! Questa è sembrata la risposta più utile, anche se per una lingua specifica dovrebbero esistere librerie per altre lingue in generale, come .NET e C ++;
iiridescente,

3
In realtà, qualsiasi codice che non utilizza una libreria dovrebbe essere rifiutato nella revisione del codice. Nella rara possibilità che non esistano librerie, la risposta sarebbe scriverne una tu stesso anziché incollare stringhe grezze.
Gort il robot


Python ha os.path.join. PowerShell ha join-path. Vorrei aggiungere qualcosa a questa risposta. Ho scoperto che se hai bisogno di percorsi di file in più pezzi, rende il tuo codice molto fragile se fai ipotesi su qualcuno di essi che ha percorsi di file in luoghi particolari. L'uso di queste classi non solo aiuta con la portabilità, ma gestisce anche tutti i possibili casi limite (barra su entrambe le estremità da unire, barra su un solo lato, nessuna barra tra tutti). Questa flessibilità è preziosa quando si trascinano percorsi di file in un file di configurazione.
jpmc26,

21

Si noti che in .NET è necessario utilizzare il metodo Path.Combine.

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

La ragione di ciò è che "conosce" i caratteri corretti da utilizzare durante la costruzione dei nomi delle cartelle.

Questo elimina il "problema" della correzione pre o post.


4
os.path.join fa sostanzialmente la stessa cosa anche per Python
StarWeaver il

Si noti che Path.Combine non li ottiene fuori dal business di preoccuparsi il separatore: stackoverflow.com/questions/53102/...
jmoreno

1
@jmoreno - Nel mio esempio NON ci sono separatori. La domanda a cui ti sei collegato ha dei separatori con codice fisso e se fondamentalmente sbagliata perché il secondo percorso è un percorso assoluto.
Erno

Stai attento, però. Non sono sicuro di .NET, ma os.path.join('src', '../../../your_secret_stuff') è valido in Python; in altre parole, non usare ciecamente questi metodi su input dell'utente.
sapi,

@sapi - Naturalmente, l'input dell'utente dovrebbe sempre essere igienizzato, ma questa è la responsabilità del programmatore, non dell'API.
Erno,

5

Quando costruisco percorsi uso spesso una funzione che aggiunge la barra finale se non è già presente. Quindi i percorsi possono essere costruiti come:

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

dove fs () aggiunge una barra finale se necessario.


5

Cartelle e file differiscono solo per un aspetto: le cartelle terminano con una barra in cui i file non lo sono. Inoltre, i percorsi assoluti iniziano con un /dove i percorsi relativi no. Se si utilizzano questi percorsi e file concatenati in modo coerente, non dovrebbe essere un problema.

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

Concatenare insieme due percorsi assoluti non ha senso, poiché il secondo percorso dovrebbe essere relativo al primo. Concatenare insieme due percorsi relativi non è un problema, ma potrebbe portare a comportamenti indefiniti se il programma non sa dove si trova il percorso relativo.


Questo probabilmente ha risposto meglio alla mia domanda originale, penso di capire meglio i percorsi dei file, anche se, come hanno detto Stephen C ed Erno, le librerie di lingue sono la migliore prima scommessa. Ciò spiega meglio la convenzione. Grazie!
iiridescente,

Percorsi o URL del file system?
Mr White,

1
A tutti gli effetti, puoi applicarlo anche su uri. Un uri assoluto inizierebbe con un protocollo, ma a parte questo sarebbe lo stesso penso.
Sumurai8

Non sono sicuro di come funzioni l'output. Quando lo faccio ottengo:var a = "/my/path" + "css/" + "test.css"; //Output: "/my/pathcss/test.css"
Damon il

1
@Damon Ho fatto una modifica. absolutepathavrebbe dovuto finire con una barra, perché è un percorso. In qualche modo l'ho trascurato quando ho scritto questo.
Sumurai8,

4

Penso che non ci sia magia o "pratica comune" su come implementare i percorsi, ma certamente la concatenazione delle stringhe non è la strada da percorrere. Puoi sviluppare la tua API per gestire i casi, ma potrebbe richiedere qualche sforzo. In particolare, dovresti stare attento alle diverse piattaforme. Ad esempio, in Windows\ è il separatore mentre in sistemi basati su Unix /è il separatore.

Non ho familiarità con le librerie Javascript, ma sono sicuro che ci dovrebbero essere librerie per la gestione di questi casi. In Java, ad esempio, è possibile utilizzare l' API Path per gestire operazioni di percorso indipendenti dalla piattaforma.


3
Windows attualmente supporta /il delimitatore del nome del percorso. Questo ha bisogno di stranezze nella riga di comando, ma le API di I / O dei file funzionano bene con la barra.
Ruslan,

en.wikipedia.org/wiki/… "l'API di sistema di Windows accetta la barra, e quindi tutti gli esempi Unix sopra dovrebbero funzionare. Ma molte applicazioni su Windows interpretano una barra per altri scopi o la trattano come un carattere non valido e quindi richiedono di te per inserire la barra rovesciata, in particolare la shell cmd.exe (spesso denominata "terminale" come in genere viene eseguita in una finestra del terminale). "
Mooing Duck

0

La mia preferenza personale è questa:

var assets = "/images"

var sounds = assets+"/sounds"

Uso sempre percorsi assoluti ( /images/...), mi sembra meno soggetto a errori. È anche più folle da usare var sounds = assets+"/sounds"perché anche se assetsavessi una barra finale e tu finissi /images//sounds, sarebbe comunque risolto /images/sounds. L'unica dichiarazione di non responsabilità è che dipende dal gestore della richiesta. Apache sembra gestirlo bene (almeno alcune versioni / configurazioni, vedi http://www.amazon.com//gp//site-directory//ref=nav_sad ). Con l'altro modo in cui ti ritroveresti /imagessounds, non così infallibile :) C'è anche la possibilità di verificare la presenza di doppie barre e di pulirle. Non un'opzione con l'altro approccio.


11
In tutti i contesti che conosco, un percorso che inizia con una barra ( /) è un percorso assoluto , non un percorso relativo. O lo intendevi solo per sezioni di percorso diverse dalla prima?
Bart van Ingen Schenau,

@BartvanIngenSchenau Concordo pienamente con te e li chiamo così da anni, ma ogni volta che leggo un articolo scritto da uno sviluppatore di front-end si riferiscono a loro come percorsi relativi. Non volevo fare ipotesi, quindi immagino di aver scelto il minore dei due mali ...? Ora che so di avere alcune persone dalla mia parte, aggiornerò la mia risposta :)
rpaskett,

2
Per gli sviluppatori Web, /somewhereè un percorso relativo perché non include l'host, quindi il browser lo cercherà in base all'host della pagina corrente ... Nel mondo Web, http://here/somewhereè un URI assoluto ed /somewhereelseè relativo a quello. Nel mondo del file system, /somewhereè assoluto, proveniente dalla radice /, e "somewhereelse" è relativo alla directory di lavoro corrente.
Rob

3
@RobY, rpaskett: passando da RFC3986 (l'RFC che definisce gli URI), http://here/somewhereè un URI con un percorso assoluto, /somewhereè un riferimento relativo con un percorso assoluto ed somewhere/elseè un riferimento relativo con un percorso relativo. Apparentemente, in quei circoli "percorso relativo" viene utilizzato per fare riferimento a un riferimento relativo.
Bart van Ingen Schenau

1
@BartvanIngenSchenau: in Windows, un percorso che inizia con una barra è un percorso relativo ed è relativo a CWD. en.wikipedia.org/wiki/…
Mooing Duck

0

In Smalltalk è semplice definire il metodo / in String in modo che funzioni così:

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

Ecco una semplice implementazione del metodo (puoi renderlo migliore):

/ 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

Nota : si potrebbe anche voler prestare maggiore attenzione ai casi di confine, come '' / '', 'x/' / ''ecc, al fine di determinare il comportamento corretto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.