从文件名中获取目录名

我有一个文件名(C:\folder\foo.txt) ,需要在 C + + 中检索文件夹名(C:\folder)。在 C # 中,我会这样做:

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

有没有一个函数可以在 C + + 中用来从文件名中提取路径?

165097 次浏览

Example from 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;
}

Standard C++ won't do much for you in this regard, since path names are platform-specific. You can manually parse the string (as in glowcoder's answer), use operating system facilities (e.g. http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx ), or probably the best approach, you can use a third-party filesystem library like boost::filesystem.

Use boost::filesystem. It will be incorporated into the next standard anyway so you may as well get used to it.

Using Boost.Filesystem:

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

There is a standard Windows function for this, PathRemoveFileSpec. If you only support Windows 8 and later, it is highly recommended to use PathCchRemoveFileSpec instead. Among other improvements, it is no longer limited to MAX_PATH (260) characters.

_splitpath is a nice CRT solution.

Just use this: ExtractFilePath(your_path_file_name)

Why does it have to be so complicated?

#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
}

In C++17 there exists a class std::filesystem::path using the method 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';
}

Possible output:

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"

I'm so surprised no one has mentioned the standard way in Posix

Please use basename / dirname constructs.

man basename

 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

You may need p.parent_path().filename() to get name of parent folder.