Bir dosya adından bir dizin adı almak


85

Bir dosya ismim var (C: \ klasör \ foo.txt) ve yönetilmeyen C ++ 'da klasör adını (C: \ klasör) almam gerekiyor. C # 'da şöyle bir şey yapardım:

string folder = new FileInfo("C:\folder\foo.txt").DirectoryName;

Yönetilmeyen C ++ 'da yolu dosya adından çıkarmak için kullanılabilecek bir işlev var mı?

Yanıtlar:


20

Bunun için standart bir Windows işlevi vardır: PathRemoveFileSpec . Yalnızca Windows 8 ve sonraki sürümleri destekliyorsanız, bunun yerine PathCchRemoveFileSpec kullanmanız önemle tavsiye edilir . Diğer iyileştirmelerin yanı sıra, artık MAX_PATH(260) karakterle sınırlı değil .


2
Bu işlevin artık kullanımdan kaldırıldığını unutmayın. Microsoft'un önerisi bunun yerine PathCchRemoveFileSpec'i kullanmaktır.
Varsayılan

1
@Default: PathCchRemoveFileSpec yalnızca Windows 8'den itibaren kullanılabilir. Windows Vista ve 7 hala desteklendiğinden, PathRemoveFileSpec de öyle .
IInspectable

154

Boost.Filesystem Kullanımı:

boost::filesystem::path p("C:\\folder\\foo.txt");
boost::filesystem::path dir = p.parent_path();

2
p.remove_filename()pyerinde değiştirilecek ve daha verimli bir şekilde uygulanabilirp = p.parent_path()
Peter Cordes

Dizinlerle de ilgileniyorsanız parent_path(), "C:\\folder"bunun sonuçlanacağına dikkat edin "C:".
Semjon Mössinger

pek çok destek std'ye yükseltilir, bu yüzden şunu da deneyin .... dahil <filesystem> .... std :: deneysel :: dosya sistemi :: yol p ("C: \\ klasör \\ foo.txt");
S Meaden

72

Http://www.cplusplus.com/reference/string/string/find_last_of/ adresinden örnek

// string::find_last_of
#include <iostream>
#include <string>
using namespace std;

void SplitFilename (const string& str)
{
  size_t found;
  cout << "Splitting: " << str << endl;
  found=str.find_last_of("/\\");
  cout << " folder: " << str.substr(0,found) << endl;
  cout << " file: " << str.substr(found+1) << endl;
}

int main ()
{
  string str1 ("/usr/bin/man");
  string str2 ("c:\\windows\\winhelp.exe");

  SplitFilename (str1);
  SplitFilename (str2);

  return 0;
}

1
Buradaki en iyi asgari çözüm budur.
plasmacel

42

C ++ 17'de std::filesystem::pathyöntemi kullanan bir sınıf vardır parent_path.

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    for(fs::path p : {"/var/tmp/example.txt", "/", "/var/tmp/."})
        std::cout << "The parent path of " << p
                  << " is " << p.parent_path() << '\n';
}

Olası çıktı:

The parent path of "/var/tmp/example.txt" is "/var/tmp"
The parent path of "/" is ""
The parent path of "/var/tmp/." is "/var/tmp"

3
Bir .remove_filename()yöntem de var .
Qqwy

1
Teşekkürler @Qqwy, yanıttaki yaklaşımdan farklı olarak doğru ve beklenen sonuçları elde etmek için bu yöntemle dizin yolunu kullanmaya da izin veriyor
Herrgott

13

Neden bu kadar karmaşık olmak zorunda?

#include <windows.h>

int main(int argc, char** argv)         // argv[0] = C:\dev\test.exe
{
    char *p = strrchr(argv[0], '\\');
    if(p) p[0] = 0;

    printf(argv[0]);                    // argv[0] = C:\dev
}

10
Bu taşınabilir değil. Linux'ta yol ayırıcı '/' dir. std :: filesystem :: path standart ve taşınabilirdir.
Rémi

7
 auto p = boost::filesystem::path("test/folder/file.txt");
 std::cout << p.parent_path() << '\n';             // test/folder
 std::cout << p.parent_path().filename() << '\n';  // folder
 std::cout << p.filename() << '\n';                // file.txt

p.parent_path().filename()Ana klasörün adını almanız gerekebilir .


5

Boost :: filesystem kullanın. Yine de bir sonraki standarda dahil edilecek, böylece buna alışabilirsiniz.


1
Hangi standarttan bahsediyorsun? Yükseltmeden çok şeyin C ++ std lib'ye eklendiğini biliyorum, dosya sistemi de eklenecek?
McLeary

7
"Yine de bir sonraki standarda dahil edilecek" Ve öyle değil
Anton K

@AntonK belki C ++ 2017?
Alessandro Jacopson

6
@AlessandroJacopson Cool, C ++ 17'ye dahil görünüyor - en.cppreference.com/w/cpp/filesystem
Anton K


1

Posix'te kimsenin standart yoldan bahsetmemesine çok şaşırdım

Lütfen basename / dirnameyapıları kullanın .

adam temel adı


1
POSIX işlevlerinin dezavantajları vardır. Özellikle, geçirdiğiniz arabelleği değiştirebilirler (gerçekten imzanın olduğu basname(char * path)ve olmadığı anlamına gelir basename(const char * path)) ve bunu yapmayan uygulamalar, onları iş parçacığı güvenli olmayan hale getiren statik bir arabellek kullanmak zorunda gibi görünür (prensipte siz dinamik olarak ayrılmış sonuçlar da döndürebilir, ancak bu sizi allocC ++ 'da garip olan aile işlevlerine bağımlı hale getirir ).
dmckee --- eski moderatör yavru kedi

-1

Yol adları platforma özgü olduğundan, standart C ++ bu konuda sizin için fazla bir şey yapmayacaktır. Dizeyi manuel olarak ayrıştırabilir (glowcoder'ın cevabında olduğu gibi), işletim sistemi olanaklarını (ör. Http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx ) veya muhtemelen en iyi yaklaşım, boost :: filesystem gibi üçüncü taraf bir dosya sistemi kitaplığı kullanabilirsiniz.


Standardın C ++ 1z'si şu anda destek dosya sistemi kitaplığını benimsemeye çalışıyor ve platform dostu olma özelliğini çok daha az bir sorun haline getiriyor. Hala en azından MSVC için deneysel başlıklarda.
kayleeFrye_onDeck

-6

Sadece şunu kullanın: ExtractFilePath (your_path_file_name)


5
Bunun bir Delphi yöntemi olduğuna inanıyorum, C ++ 'da bir şey değil.
Ian Hunter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.