У меня есть имя файла (C:\folder\foo.txt), и мне нужно получить имя папки (C:\folder) в неуправляемом С++. В С# я бы сделал что-то вроде этого:
string folder = new FileInfo("C:\folder\foo.txt").DirectoryName;
Есть ли функция, которая может использоваться в неуправляемом С++ для извлечения пути из имени файла?
Для этого есть стандартная функция Windows, PathRemoveFileSpec. Если вы поддерживаете только Windows 8 и более поздние версии, рекомендуется использовать PathCchRemoveFileSpec. Среди других улучшений он больше не ограничен символами MAX_PATH
(260).
Использование Boost.Filesystem:
boost::filesystem::path p("C:\\folder\\foo.txt");
boost::filesystem::path dir = p.parent_path();
p.remove_filename()
изменит p
на месте и может быть реализован более эффективно, чем p = p.parent_path()
parent_path()
из "C:\\folder"
приведет к "C:"
.
Пример из http://www.cplusplus.com/reference/string/string/find_last_of/
// 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;
}
Почему это должно быть настолько сложно?
#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
}
Использовать boost:: filesystem. В любом случае, он будет включен в следующий стандарт, чтобы вы могли привыкнуть к нему.
Согласно cppreference.com, существует экспериментальная поддержка библиотеки заголовков для С++ 17/1z с классом std::experimental::filesystem::path
с использованием метода parent_path
.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::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';
}
Возможный выход:
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"
.remove_filename()
.
_ splitpath - это хорошее решение для CRT.
Стандарт С++ в этом отношении не поможет, поскольку имена путей зависят от платформы. Вы можете вручную разобрать строку (как в ответе на glowcoder), использовать средства операционной системы (например, http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx) или, возможно, лучший подход, вы можете использовать стороннюю библиотеку файловой системы, такую как boost:: filesystem.
Я так удивлен, что никто не упомянул стандартный способ в Posix
Используйте конструкции basename / dirname
.
man basename
basname(char * path)
а не basename(const char * path)
), и реализации, которые этого не делают, должны использовать статический буфер, который делает их поточно-небезопасными (в принципе, вы также можете возвращать динамически распределяемые результаты, но это делает вас зависимым от функций семейства alloc
что неудобно в C ++).
Просто используйте это: ExtractFilePath (your_path_file_name)