Como encontro o diretório pai em C #?


86

Eu uso este código para encontrar o diretório de depuração

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

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

Como posso encontrar a pasta pai conforme mostrado abaixo?

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


16
Por que as pessoas sempre usam ToString () em strings?
Hogan

2
@Hogan, caso o imóvel mude? : D
musefan

Respostas:


128

Você pode usar System.IO.Directory.GetParent()para recuperar o diretório pai de um determinado diretório.


23
se o diretório tiver barras no final, você deve chamar GetParent duas vezes
northben

3
Isso parece funcionar em caminhos relativos (surpresa feliz), mas não tem como você obter o resultado de volta (surpresa infeliz).
Adam,

15
Você pode evitar o problema de barras finais ao usar DirectoryInfo.Parent. por exemplo new System.IO.DirectoryInfo("c:/path/to/somewhere//").Parent. @northben
mcNux

47
string parent = System.IO.Directory.GetParent(str_directory).FullName;

Veja BOL


35

Se você anexar ..\..ao seu caminho existente, o sistema operacional navegará corretamente na pasta dos avós.

Isso deve fazer o trabalho:

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

Se você navegar por esse caminho, você navegará no diretório dos avós.


1
Isso parecia bom, mas infelizmente dá C: \ Users \ Masoud \ Documents \ Visual Studio 2008 \ Projects \ MyProj \ MyProj \ bin \ Debug \ .. \ ..
StuartQ

Sim e se você navegar por esse caminho, você navegará no diretório pai-pai.
Pierre-Alain Vigeant

Justificativa, vou remover o downvote, embora tenha que editar em seu comentário para devolver o ponto.
StuartQ,

3
O resultado de "Path.Combine" pode ser passado por "Path.GetFullPath" para limpá-lo. Isso é para chegar a "C: \ Users \ Masoud \ Documents \ Visual Studio 2008 \ Projects \ MyProj \ MyProj"
Konstantin

1
Esta é a melhor maneira de subir vários níveis na árvore de diretórios
Trung Le

19

Descobri que as variantes de System.IO.Path.Combine(myPath, "..")são as mais fáceis e confiáveis. Ainda mais se o que northben diz for verdade, que GetParent requer uma chamada extra se houver uma barra final. Isso, para mim, não é confiável.

Path.Combine garante que você nunca errará com barras.

..se comporta exatamente como em qualquer outro lugar do Windows. Você pode adicionar qualquer número de \..a um caminho no cmd ou explorer e ele se comportará exatamente como eu descrevo abaixo.

Alguns ..comportamentos básicos :

  1. Se houver um nome de arquivo, ele ..será cortado:

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

  1. Se o caminho for um diretório, ..subirá um nível:

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

  1. ..\.. segue as mesmas regras, duas vezes seguidas:

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

  1. E isso tem exatamente o mesmo efeito:

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


1
Concordo que esse método tem a vantagem de funcionar independentemente de o caminho ter ou não uma barra invertida final. E em situações em que você deseja um caminho simples sem os pontos, você pode aplicar Path.GetFullPath (() ao resultado.
RenniePet

1
Dois anos depois e eu me encontro de volta aqui. Esteja ciente de que Path.GetFullPath (() normalmente retorna um caminho sem nenhuma barra invertida final, mas quando você chega ao diretório raiz, por exemplo "E: \", então há uma barra invertida.
RenniePet

Isso não funciona, nem com .NET 4.7 nem .NET Core 2.1: Path.Combine(@"D:\Grandparent\Parent\Child.txt", @"..")=D:\Grandparent\Parent\Child.txt\..
Métoule

Isso não trunca o nome do arquivo para mim, pelo menos no MacOS via Unity.
supergra

@ Métoule @supergra Eu vejo a confusão. Path.Combinenão trunca a própria string. O caminho , uma vez usado para acessar o sistema de arquivos, tem o efeito desejado. No entanto, concordo que isso é abaixo do ideal. Veja minha resposta mais recente nesta página para uma abordagem que modifica a string em vez de precisar do sistema de arquivos para resolver o caminho.
Timo

11

Para obter um diretório 'avós', chame Directory.GetParent () duas vezes:

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

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

8

Directory.GetParenté provavelmente uma resposta melhor, mas para ser completo há um método diferente que leva string e retorna string: Path.GetDirectoryName.

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

1
Lembre-se de que Path.GetDirectoryName não funciona bem com caminhos relativos .. Directory.GetParent sim.
nawfal

6

Como isso:

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

Boa sorte!


1
myDirectory.Parent.ToString () retorna o nome da subpasta, não o caminho completo, exatamente o que eu estava procurando. Além disso, em vez de fazer Directory.GetParent (Directory.GetParent (str_directory) .ToString ()); como mostrado acima, simplesmente usando myDirectory.parent.parent.ToString () obtém o 'avô'.
Weihui Guo

1
Acho esse método o melhor porque ele lida com o caso em que o caminho do diretório tem barras finais. Por outro lado, se você usar Directory.GetParent (), terá que chamá-lo duas vezes para remover as barras e obter o pai real.
Magnus


3

Para evitar problemas com trailing \, chame-o desta forma:

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

1
Você pode usar TrimEndse quiser apenas remover o trailing `'s . I'm not sure if a leading `é significativo em outros sistemas operacionais.
Walter Stabosz

2

Para obter sua solução, tente isso

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

2

Esta é a forma mais comum - realmente depende do que você está fazendo exatamente: (para explicar, o exemplo abaixo removerá os últimos 10 caracteres que você pediu, no entanto, se houver algumas regras de negócios que direcionam sua necessidade para encontrar um local específico, você deve usá-los para recuperar o local do diretório, não encontrar o local de outra coisa e modificá-la.)

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

O primeiro só funciona se você souber que os últimos caracteres são exatamente \bin\Debug , sem nenhum ` and no other path, so it's extraordinarily fragile. Your second doesn't work because Environment.CurrentDirectory` à direita é uma string e as strings não têm uma Parentpropriedade.
Joe White

@Joe, retirei o segundo. Mas acho que essa é uma resposta válida, se o caminho for sempre \ bin \ debug vai funcionar. E, como eu disse, o OP deve realmente observar qual é o BR que leva à necessidade do diretório e usar uma abordagem diferente (provavelmente usaria uma entrada de configuração, mas estou supondo que o BR e a estrutura do programa)
Hogan

Embora não seja perfeito e frágil, foi a única solução que funcionou para mim. Edição sugerida: "str_directory.length" deve ser "str_directory.Length", L minúsculo não é aceitável.
OverMars

2

Ninguém forneceu uma solução que funcionasse de forma cruzada. Eu sei que não foi perguntado especificamente, mas estou trabalhando em um ambiente linux onde a maioria das soluções (como no momento em que publiquei isso) forneceria um erro.

Separadores de caminho de codificação (bem como outras coisas) darão um erro em qualquer coisa, exceto nos sistemas Windows.

Na minha solução original, usei:

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

No entanto, depois de ver algumas das respostas aqui, ajustei para ser:

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

2

Uma vez que nada mais que eu encontrei ajuda a resolver isso de uma forma verdadeiramente normalizada, aqui está outra resposta.

Observe que algumas respostas a perguntas semelhantes tentam usar o Uri tipo, mas isso também luta com barras finais e sem barras finais.

Minha outra resposta nesta página funciona para operações que colocam o sistema de arquivos para funcionar, mas se quisermos ter o caminho resolvido agora (como para fins de comparação), sem passar pelo sistema de arquivos, C:/Temp/..eC:/ seria considerado diferente. Sem passar pelo sistema de arquivos, navegar dessa maneira não nos fornece um caminho normalizado e adequadamente comparável.

O que podemos fazer?

Vamos desenvolver a seguinte descoberta:

Path.GetDirectoryName(path + "/") ?? ""será confiável dar-nos um caminho de diretório sem uma barra final .

  • Adicionar uma barra (como string, não como char) tratará um nullcaminho da mesma forma que trata "".
  • GetDirectoryName irá abster-se de descartar o último componente do caminho graças à barra adicionada.
  • GetDirectoryName irá normalizar barras e pontos de navegação.
  • Isso inclui a remoção de quaisquer barras finais.
  • Isso inclui ..recolher navegando para cima.
  • GetDirectoryNamevai voltar nullpara um caminho vazio, ao qual nos unimos "".

Como usamos isso?

Primeiro, normalize o caminho de entrada :

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

Em seguida, podemos obter o diretório pai e podemos repetir essa operação quantas vezes quiser para navegar mais para cima:

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

Observe que nunca mexemos no sistema de arquivos. Nenhuma parte do caminho precisa existir, como existiria se o tivéssemos usado DirectoryInfo.


1

Você não deve tentar fazer isso. Environment.CurrentDirectory fornece o caminho do diretório executável. Isso é consistente, independentemente de onde o arquivo .exe esteja. Você não deve tentar acessar um arquivo que se presume estar em uma localização relativa ao contrário

Eu sugiro que você mova qualquer recurso que deseja acessar para um local local. De um diretório do sistema (como AppData)


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

Se você limpar o " bin\Debug\" nas propriedades do projeto -> Build -> Caminho de saída, você pode apenas usarAppDomain.CurrentDomain.BaseDirectory

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.