Jak znaleźć katalog nadrzędny w C #?


85

Używam tego kodu do znajdowania katalogu debugowania

public string str_directory = Environment.CurrentDirectory.ToString();

"C:\\Users\\Masoud\\Documents\\Visual Studio 2008\\Projects\\MyProj\\MyProj\\bin\\Debug"

Jak mogę znaleźć folder nadrzędny, jak pokazano poniżej?

"C:\\Users\\Masoud\\Documents\\Visual Studio 2008\\Projects\\MyProj\\MyProj"


15
Dlaczego ludzie zawsze używają ToString () na ciągach?
Hogan

1
@Hogan, na wypadek gdyby nieruchomość się zmieniła? : D
musefan

Odpowiedzi:


126

Możesz użyć, System.IO.Directory.GetParent()aby pobrać katalog nadrzędny danego katalogu.


21
jeśli katalog zawiera końcowe ukośniki, należy dwukrotnie wywołać GetParent
northben

2
Wydaje się, że działa to na ścieżkach względnych (radosna niespodzianka), ale nie ma możliwości odzyskania wyniku (nieszczęśliwa niespodzianka).
Adam,

14
Możesz uniknąć problemu z końcowymi ukośnikami, używając zamiast tego DirectoryInfo.Parent. np new System.IO.DirectoryInfo("c:/path/to/somewhere//").Parent. @northben
mcNux


35

Jeśli dołączysz ..\..do istniejącej ścieżki, system operacyjny poprawnie przegląda folder nadrzędny.

To powinno wystarczyć:

System.IO.Path.Combine("C:\\Users\\Masoud\\Documents\\Visual Studio 2008\\Projects\\MyProj\\MyProj\\bin\\Debug", @"..\..");

Jeśli przejrzysz tę ścieżkę, przejrzysz katalog nadrzędny.


1
Wyglądało to ładnie, ale niestety daje C: \ Users \ Masoud \ Documents \ Visual Studio 2008 \ Projects \ MyProj \ MyProj \ bin \ Debug \ .. \ ..
StuartQ

Tak i jeśli przejrzysz tę ścieżkę, przejrzysz katalog nadrzędny-nadrzędny.
Pierre-Alain Vigeant

Słuszna uwaga, usunę głos przeciw, chociaż będę musiał zmienić twój komentarz, aby oddać punkt.
StuartQ

3
Wynik „Path.Combine” można przekazać przez „Path.GetFullPath”, aby go wyczyścić. To znaczy dostać się do „C: \ Users \ Masoud \ Documents \ Visual Studio 2008 \ Projects \ MyProj \ MyProj”
Konstantin

1
To najlepszy sposób na przejście o kilka poziomów w górę w drzewie katalogów
Trung Le

18

Odkryłem, że warianty System.IO.Path.Combine(myPath, "..")są najłatwiejsze i najbardziej niezawodne. Tym bardziej, jeśli prawdą jest to, co mówi northben, to GetParent wymaga dodatkowego wywołania, jeśli na końcu znajduje się ukośnik. To dla mnie niewiarygodne.

Path.Combine zapewnia, że ​​nigdy nie pomylisz się z ukośnikami.

..zachowuje się dokładnie tak samo, jak wszędzie indziej w systemie Windows. Możesz dodać dowolną liczbę \..do ścieżki w cmd lub eksploratorze i będzie zachowywać się dokładnie tak, jak opisuję poniżej.

Niektóre podstawowe ..zachowania:

  1. Jeśli istnieje nazwa pliku, ..odetnie ją:

Path.Combine(@"D:\Grandparent\Parent\Child.txt", "..") => D:\Grandparent\Parent\

  1. Jeśli ścieżka jest katalogiem, ..przejdzie na wyższy poziom:

Path.Combine(@"D:\Grandparent\Parent\", "..") => D:\Grandparent\

  1. ..\.. przestrzega tych samych zasad, dwa razy z rzędu:

Path.Combine(@"D:\Grandparent\Parent\Child.txt", @"..\..")=> D:\Grandparent\ Path.Combine(@"D:\Grandparent\Parent\", @"..\..")=>D:\

  1. I to ma dokładnie ten sam efekt:

Path.Combine(@"D:\Grandparent\Parent\Child.txt", "..", "..")=> D:\Grandparent\ Path.Combine(@"D:\Grandparent\Parent\", "..", "..")=>D:\


1
Zgadzam się, że ta metoda ma tę zaletę, że działa niezależnie od tego, czy ścieżka ma końcowy ukośnik odwrotny. A w sytuacjach, w których chcesz mieć prostą ścieżkę bez kropek, możesz zastosować Path.GetFullPath (() do wyniku.
RenniePet

1
Dwa lata później znów tu jestem. Należy pamiętać, że Path.GetFullPath (() normalnie zwraca ścieżkę bez końcowego ukośnika odwrotnego, ale kiedy dojdziesz do katalogu głównego, na przykład „E: \”, jest tam ukośnik odwrotny.
RenniePet

To nie działa, ani z .NET 4.7, ani .NET Core 2.1: Path.Combine(@"D:\Grandparent\Parent\Child.txt", @"..")=D:\Grandparent\Parent\Child.txt\..
Métoule,

To nie powoduje obcięcia nazwy pliku, przynajmniej na MacOS przez Unity.
supergra

@ Métoule @supergra Widzę zamieszanie. Path.Combinenie obcina samego ciągu. Ścieżka używana kiedyś do uzyskania dostępu do systemu plików ma zamierzony skutek. Zgadzam się jednak, że jest to nieoptymalne. Zobacz moją najnowszą odpowiedź na tej stronie, aby poznać podejście, które modyfikuje ciąg zamiast potrzebować systemu plików do rozwiązania ścieżki.
Timo

11

Aby uzyskać katalog dla dziadków, wywołaj Directory.GetParent () dwa razy:

var gparent = Directory.GetParent(Directory.GetParent(str_directory).ToString());

1
var gparent = Directory.GetParent(str_directory).Parent; // Cleaner?
JohnB

8

Directory.GetParentPrawdopodobnie jest to lepsze rozwiązanie, ale dla kompletności istnieje inna metoda, która przyjmuje i zwraca ciąg znaków: Path.GetDirectoryName.

string parent = System.IO.Path.GetDirectoryName(str_directory);

1
Pamiętaj, że Path.GetDirectoryName nie działa dobrze ze ścieżkami względnymi .. Directory.GetParent tak.
nawfal

6

Lubię to:

System.IO.DirectoryInfo myDirectory = new DirectoryInfo(Environment.CurrentDirectory);
string parentDirectory = myDirectory.Parent.FullName;

Powodzenia!


1
myDirectory.Parent.ToString () zwraca nazwę podfolderu, a nie pełną ścieżkę, dokładnie to, czego szukałem. Ponadto zamiast robić Directory.GetParent (Directory.GetParent (str_directory) .ToString ()); jak pokazano powyżej, po prostu używając myDirectory.parent.parent.ToString () uzyskuje się „dziadek”.
Weihui Guo

1
Uważam tę metodę za najlepszą, ponieważ obsługuje przypadek, w którym ścieżka katalogu zawiera końcowe ukośniki. Natomiast jeśli używasz Directory.GetParent (), musisz wywołać go dwukrotnie, aby usunąć ukośniki, a następnie uzyskać faktyczny element nadrzędny.
Magnus,


3

Aby uniknąć problemów z końcowym \, nazwij to w ten sposób:

  string ParentFolder =  Directory.GetParent( folder.Trim('\\')).FullName;

1
Możesz użyć, TrimEndjeśli chcesz tylko usunąć końcowe `'s . I'm not sure if a leading `jest istotne w innych systemach operacyjnych.
Walter Stabosz

2

Aby uzyskać rozwiązanie, spróbuj tego

string directory = System.IO.Directory.GetParent(System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString()).ToString();

2

To jest najczęstszy sposób - to naprawdę zależy od tego, co dokładnie robisz: (Aby wyjaśnić, poniższy przykład usunie ostatnie 10 znaków, o które prosiłeś, jednak jeśli istnieją jakieś zasady biznesowe, które napędzają twoje potrzeby Aby znaleźć określoną lokalizację, należy użyć ich do pobrania lokalizacji katalogu, a nie do znajdowania lokalizacji czegoś innego i modyfikowania jej).

// remove last 10 characters from a string
str_directory = str_directory.Substring(0,str_directory.Length-10);

Twój pierwszy działa tylko wtedy, gdy wiesz, że ostatnie znaki są dokładnie \bin\Debug , bez końcowego katalogu ` and no other path, so it's extraordinarily fragile. Your second doesn't work because Environment.CurrentDirectory` jest łańcuchem, a łańcuchy nie mają Parentwłaściwości.
Joe White

@Joe, usunąłem 2nd. Ale myślę, że to poprawna odpowiedź, jeśli ścieżka zawsze będzie \ bin \ debug, zadziała. I jak powiedział OP powinien naprawdę spojrzeć na to, co BR który napędza zapotrzebowanie na katalogu i użyć innego podejścia (pewnie bym użyć wpisu konfiguracji, ale zgaduję na BR i struktury programu.)
Hogan

Chociaż nie jest doskonały i delikatny, jest to jedyne rozwiązanie, które dla mnie zadziałało. Sugerowana edycja: „str_directory.length” powinna mieć wartość „str_directory.Length”, małe litery L są niedopuszczalne.
OverMars

2

Nikt nie dostarczył rozwiązania, które działałoby w różnych formach. Wiem, że nie było to specjalnie zadane, ale pracuję w środowisku linuxowym, w którym większość rozwiązań (jak w momencie, gdy to publikowałem) powodowałaby błąd.

Zakodowane separatory ścieżek (a także inne rzeczy) spowodują błąd w innych systemach niż Windows.

W moim oryginalnym rozwiązaniu zastosowałem:

char filesep = Path.DirectorySeparatorChar;
string datapath = $"..{filesep}..{filesep}";

Jednak po zobaczeniu niektórych odpowiedzi tutaj dostosowałem to tak, aby było:

string datapath = Directory.GetParent(Directory.GetParent(Directory.GetCurrentDirectory()).FullName).FullName; 

2

Ponieważ nic innego, co znalazłem, nie pomaga rozwiązać tego w prawdziwie znormalizowany sposób, oto inna odpowiedź.

Zwróć uwagę, że w niektórych odpowiedziach na podobne pytania próbuje się używać tego Uritypu, ale to problem z końcowymi ukośnikami i bez końcowych ukośników.

Moja druga odpowiedź na tej stronie działa w przypadku operacji, które uruchamiają system plików, ale jeśli chcemy teraz mieć rozwiązaną ścieżkę (na przykład w celach porównawczych), bez przechodzenia przez system plików, C:/Temp/..i C:/zostanie uznana za inną. Bez przechodzenia przez system plików nawigacja w ten sposób nie zapewnia nam znormalizowanej, odpowiednio porównywalnej ścieżki.

Co możemy zrobić?

Będziemy opierać się na następującym odkryciu:

Path.GetDirectoryName(path + "/") ?? ""będzie niezawodnie dają nam ścieżkę bez ukośnika .

  • Dodanie ukośnika (jako string, nie jako char) spowoduje traktowanie nullścieżki tak samo, jak traktuje "".
  • GetDirectoryName powstrzyma się od odrzucenia ostatniego komponentu ścieżki dzięki dodanemu ukośnikowi.
  • GetDirectoryName znormalizuje ukośniki i kropki nawigacyjne.
  • Obejmuje to usunięcie wszelkich końcowych ukośników.
  • Obejmuje to zwijanie ..przez nawigację w górę.
  • GetDirectoryNamepowrócą nullpo pustą ścieżkę, do której się zlewamy "".

Jak tego używamy?

Najpierw znormalizuj ścieżkę wejściową :

dirPath = Path.GetDirectoryName(dirPath + "/") ?? "";

Następnie możemy pobrać katalog nadrzędny i możemy powtórzyć tę operację dowolną liczbę razy, aby przejść dalej w górę:

// This is reliable if path results from this or the previous operation
path = Path.GetDirectoryName(path);

Zauważ, że nigdy nie dotknęliśmy systemu plików. Żadna część ścieżki nie musi istnieć, jak by to było, gdybyśmy skorzystali DirectoryInfo.


1

Nie powinieneś tego robić. Environment.CurrentDirectory podaje ścieżkę do katalogu wykonywalnego. Jest to spójne niezależnie od lokalizacji pliku .exe. Nie powinieneś próbować uzyskać dostępu do pliku, co do którego zakłada się, że znajduje się w odwrotnej lokalizacji względnej

Sugerowałbym przeniesienie dowolnego zasobu, do którego chcesz uzyskać dostęp, do lokalnej lokalizacji. Katalogu systemowego (na przykład AppData)


1
IO.Path.GetFullPath(@"..\..")

Jeśli wyczyścisz " bin\Debug\" we właściwościach projektu -> Kompiluj -> Ścieżka wyjściowa, możesz po prostu użyćAppDomain.CurrentDomain.BaseDirectory

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.