Як знайти батьківський каталог у C #?


85

Я використовую цей код для пошуку каталогу налагодження

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

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

Як я можу знайти батьківську папку, як показано нижче?

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


15
Чому люди завжди використовують ToString () у рядках?
Хоган

1
@Hogan, на випадок зміни власності? : D
musefan

Відповіді:


126

Ви можете використовувати System.IO.Directory.GetParent()для отримання батьківського каталогу даного каталогу.


21
якщо в каталозі є похилі риски, вам доведеться зателефонувати GetParent двічі
northben

2
Здається, це працює на відносних шляхах (щасливий сюрприз), але тоді у вас немає можливості повернути результат (нещасний сюрприз).
Адам

14
Замість цього ви можете уникнути проблеми з кінцевими косими рисками DirectoryInfo.Parent. напр new System.IO.DirectoryInfo("c:/path/to/somewhere//").Parent. @northben
mcNux


35

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

Це повинно зробити роботу:

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

Якщо ви переглянете цей шлях, ви переглянете головний батьківський каталог.


1
Це виглядало приємно, але, на жаль, дає C: \ Users \ Masoud \ Documents \ Visual Studio 2008 \ Projects \ MyProj \ MyProj \ bin \ Debug \ .. \ ..
StuartQ

Так, і якщо ви переглянете цей шлях, ви переглянете батьківсько-батьківський каталог.
Pierre-Alain Vigeant,

Справедливий момент, я зніму голос проти, хоча мені доведеться відредагувати у вашому коментарі, щоб повернути думку.
StuartQ

3
Результат "Path.Combine" можна передати через "Path.GetFullPath", щоб очистити його. Тобто дістатися до "C: \ Users \ Masoud \ Documents \ Visual Studio 2008 \ Projects \ MyProj \ MyProj"
Костянтин

1
Це найкращий спосіб піднятися на кілька рівнів у дереві каталогів
Trung Le

18

Я знайшов варіанти System.IO.Path.Combine(myPath, "..") найпростіших та найнадійніших. Навіть більше, якщо те, що каже northben, відповідає дійсності, GetParent вимагає додаткового виклику, якщо є кінцева коса риса. Для мене це ненадійно.

Path.Combine гарантує, що ви ніколи не помилитеся зі скісними рисками.

..поводиться так само, як і скрізь у Windows. Ви можете додати будь-яке число \..до шляху в cmd або explorer, і він буде поводитися точно так, як я описую нижче.

Деякі основні ..поведінки:

  1. Якщо є ім’я файлу, це ..буде відбито:

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

  1. Якщо шлях до каталогу, ..буде рухатися на рівень вище:

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

  1. ..\.. дотримується одних і тих же правил, двічі поспіль:

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

  1. І це має точно такий же ефект:

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


1
Я погоджуюся, що перевага цього методу полягає в тому, що шлях має кінцеву зворотну косу риску. А в ситуаціях, коли вам потрібен простий шлях без крапок, ви можете застосувати Path.GetFullPath (() до результату
RenniePet

1
Через два роки я знову опиняюся тут. Майте на увазі, що Path.GetFullPath (() зазвичай повертає шлях без будь-якої зворотної косої риски, але коли ви потрапляєте до кореневого каталогу, наприклад "E: \", тоді є зворотна коса
риса

Це не працює, ні з .NET 4.7, ні з .NET Core 2.1: Path.Combine(@"D:\Grandparent\Parent\Child.txt", @"..")=D:\Grandparent\Parent\Child.txt\..
Metoule

Це не скорочує ім’я файлу для мене, принаймні на MacOS через Unity.
супергра

@ Métoule @supergra Я бачу плутанину. Path.Combineне усікає сам рядок. Шлях , колись використаний для доступу до файлової системи, має передбачуваний ефект. Однак я погоджуюсь, що це неоптимально. Дивіться мою останню відповідь на цій сторінці щодо підходу, який змінює рядок, а не потребує файлової системи для вирішення шляху.
Тимо

11

Щоб отримати каталог "дідусь і бабуся", зателефонуйте Directory.GetParent () двічі :

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

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

8

Directory.GetParentце , ймовірно, краща відповідь, але для повноти картини, є інший метод , який приймає рядок і повертає рядок: Path.GetDirectoryName.

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

1
Майте на увазі, Path.GetDirectoryName погано працює з відносними шляхами .. Directory.GetParent це робить.
nawfal

6

Подобається це:

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

Удачі!


1
myDirectory.Parent.ToString () повертає ім'я підпапки, а не повний шлях, саме те, що я шукав. Крім того, замість того, щоб робити Directory.GetParent (Directory.GetParent (str_directory) .ToString ()); як показано вище, просто використовуючи myDirectory.parent.parent.ToString () отримує "бабуся і дідусь".
Вейхуей Го

1
Я вважаю цей метод найкращим, оскільки він обробляє випадок, коли шлях до каталогу має кінцеві слєші. Тоді як якщо ви використовуєте Directory.GetParent (), вам доведеться викликати його двічі, щоб видалити похилі риски, а потім отримати фактичний батько.
Магнус


3

Щоб уникнути проблем із завершенням \, назвіть це так:

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

1
Ви можете використовувати, TrimEndякщо ви хочете лише видалити завершення `'s . I'm not sure if a leading `є важливим в інших ОС.
Вальтер Стабош,

2

Щоб отримати рішення, спробуйте це

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

2

Це найпоширеніший спосіб - це насправді залежить від того, що ви точно робите: (Щоб пояснити, у наведеному нижче прикладі буде видалено останні 10 символів, саме те, про що ви просили, однак, якщо деякі ділові правила визначають ваші потреби щоб знайти конкретне розташування, ви повинні використовувати ці, щоб отримати розташування каталогу, а не знаходити розташування чогось іншого та змінювати його.)

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

Перший працює лише в тому випадку, якщо ви знаєте, що останні символи - це точно \bin\Debug , без кінцевого ` and no other path, so it's extraordinarily fragile. Your second doesn't work because середовища. CurrentDirectory` - це рядок, і рядки не мають Parentвластивості.
Joe White

@Joe, я видалив 2-го. Але я думаю, що це вірна відповідь, якщо шлях завжди \ bin \ debug, він буде працювати. І як я вже сказав, OP повинен справді поглянути на те, що таке BR, що зумовлює потребу в каталозі, і використовувати інший підхід (я б, мабуть, використовував запис конфігурації, але я здогадуюсь про BR та структуру програми.)
Hogan

Хоча це не ідеальне та крихке, єдине рішення, яке спрацювало для мене. Пропоноване редагування: "str_directory.length" має бути "str_directory.Length", нижній регістр L неприйнятний.
OverMars

2

Ніхто не запропонував рішення, яке могло б працювати у різних формах. Я знаю, що про це конкретно не запитували, але я працюю в середовищі Linux, де більшість рішень (як на той час, коли я розміщую це) дають помилку.

Розділювачі шляху жорсткого кодування (як і інші речі) дадуть помилку в будь-чому, окрім систем Windows.

У своєму оригінальному рішенні я використав:

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

Однак, побачивши деякі відповіді тут, я скоригував їх так:

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

2

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

Зверніть увагу, що деякі відповіді на подібні запитання намагаються використовувати Uri тип, але це бореться із кінцевими скісними рисками та відсутністю кінцевих скісних рисок.

Моя інша відповідь на цій сторінці працює для операцій, які запускають роботу файлової системи, але якщо ми хочемо мати вирішений шлях прямо зараз (наприклад, для порівняння), не проходячи через файлову систему, C:/Temp/..іC:/ вважатимемо іншим. Не проходячи файлову систему, навігація таким чином не забезпечує нам нормалізованого, належним чином порівнянного шляху.

Що ми можемо зробити?

Ми будемо спиратися на наступне відкриття:

Path.GetDirectoryName(path + "/") ?? "" буде надійно дати нам шлях до каталогу без слеша .

  • Додавання скісної риски (як string, не як char), nullшлях буде трактуватися так само, як і трактується "".
  • GetDirectoryName утримається від відхилення компонента останнього шляху завдяки доданій косой рисі.
  • GetDirectoryName нормалізує скісні риски та навігаційні крапки.
  • Сюди входить видалення будь-яких косих рисок.
  • Сюди входить руйнування .. за допомогою навігації вгору.
  • GetDirectoryNameповернеться nullдо порожнього шляху, котрому ми об’єднуємось"" .

Як ми цим користуємось?

Спочатку нормуйте вхідний шлях :

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

Потім ми можемо отримати батьківський каталог , і ми можемо повторити цю операцію скільки завгодно разів, щоб перейти далі:

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

Зауважте, що ми ніколи не торкалися файлової системи. Жодна частина шляху не повинна існувати, як це було б, якби ми використовували DirectoryInfo.


1

Не варто намагатися це зробити. Environment.CurrentDirectory дає вам шлях до виконуваного каталогу. Це узгоджується незалежно від того, де знаходиться файл .exe. Не слід намагатися отримати доступ до файлу, який, як передбачається, знаходиться у відносному розташуванні назад

Я б запропонував вам перенести будь-який ресурс, до якого ви хочете отримати доступ, у місцеве місце. Системного каталогу (наприклад, AppData)


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

Якщо зняти " bin\Debug\" у властивостях проекту -> Збірка -> Вихідний шлях, тоді ви можете просто використовуватиAppDomain.CurrentDomain.BaseDirectory

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