Как найти родительский каталог в C #?


86

Я использую этот код для поиска каталога отладки

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"


16
Почему люди всегда используют ToString () для строк?
Hogan

2
@Hogan, в случае изменения собственности? : D
musefan

Ответы:


128

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


23
если в каталоге есть завершающие косые черты, вы должны дважды вызвать GetParent
northben

3
Похоже, что это работает на относительных путях (счастливое удивление), но тогда у вас нет возможности вернуть результат (несчастное удивление).
Адам

15
Вы можете избежать появления косой черты в конце, используя вместо этого DirectoryInfo.Parent. напр new System.IO.DirectoryInfo("c:/path/to/somewhere//").Parent. @northben
mcNux 05


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 02

Да, и если вы просмотрите этот путь, вы перейдете к родительско-родительскому каталогу.
Пьер-Ален Вижан,

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

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

1
Это лучший способ подняться на несколько уровней в дереве каталогов
Trung Le

19

Я нашел варианты System.IO.Path.Combine(myPath, "..") которые самые простые и надежные. Более того, если то, что говорит northben, верно, то GetParent требует дополнительного вызова, если есть завершающая косая черта. На мой взгляд, это ненадежно.

Path.Combine гарантирует, что вы никогда не ошибетесь с косой чертой.

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

Некоторое базовое ..поведение:

  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 02

1
Два года спустя я снова оказываюсь здесь. Имейте в виду, что Path.GetFullPath (() обычно возвращает путь без обратной косой черты в конце, но когда вы переходите в корневой каталог, например «E: \», появляется обратная косая черта.
RenniePet

Это не работает ни с .NET 4.7, ни с .NET Core 2.1: Path.Combine(@"D:\Grandparent\Parent\Child.txt", @"..")=D:\Grandparent\Parent\Child.txt\..
Métoule

Для меня это не обрезает имя файла, по крайней мере, в MacOS через Unity.
supergra

@ Métoule @supergra Я вижу путаницу. Path.Combineне обрезает саму строку. Путь , однажды использованный для доступа к файловой системе, имеет желаемый эффект. Однако я согласен, что это неоптимально. См. Мой более поздний ответ на этой странице, чтобы узнать о подходе, который изменяет строку вместо того, чтобы файловая система требовала разрешения пути.
Timo


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 Environment.CurrentDirectory` - это строка, а строки не имеют Parentсвойства.
Joe White

@ Джо, я удалил второй. Но я думаю, что это правильный ответ, если путь всегда \ 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.