从文件名获取目录名称


85

我有一个文件名(C:\ folder \ foo.txt),我需要在非托管C ++中检索文件夹名称(C:\ folder)。在C#中,我将执行以下操作:

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

有没有可以在非托管C ++中使用的函数来从文件名中提取路径?

Answers:


20

为此,有一个标准的Windows函数PathRemoveFileSpec。如果仅支持Windows 8和更高版本,则强烈建议改用PathCchRemoveFileSpec。除其他改进外,它不再限于MAX_PATH(260)个字符。


2
请注意,此功能现已弃用。Microsoft的建议是改用PathCchRemoveFileSpec
默认值

1
@Default:PathCchRemoveFileSpec仅从Windows 8开始可用。由于仍支持Windows Vista和7,因此PathRemoveFileSpec也受支持。
IInspectable '16

153

使用Boost.Filesystem:

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

2
p.remove_filename()p就地修改,并且可能比p = p.parent_path()
Peter Cordes

如果您还可以处理目录,请注意parent_path()from"C:\\folder"会导致的事实"C:"
SemjonMössinger16年

很多Boost都升级到了std,所以也可以尝试这个....包括<filesystem> .... std :: experimental :: filesystem :: path p(“ C:\\ folder \\ foo.txt”);
S米登

72

来自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;
}

1
这是这里最好的最小解决方案。
–plasmcel

39

在C ++ 17中,存在std::filesystem::path使用方法的类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';
}

可能的输出:

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"

2
也存在一种.remove_filename()方法。
19qqwy

1
谢谢@Qqwy,它也允许将目录路径与该方法一起使用以获取正确和预期的结果,这与答案中的方法不同
Herrgott

13

为什么它必须如此复杂?

#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
这不是便携式的。Linux中的路径分隔符是“ /”。std :: filesystem ::: path是标准且可移植的。
雷米

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()获取父文件夹的名称。


5

使用boost :: filesystem。无论如何,它将被合并到下一个标准中,因此您也可以习惯它。


1
您在说什么标准?我知道很多来自boost的东西都添加到了C ++ std lib中,文件系统也会被添加吗?
McLeary

7
“无论如何它将被纳入下一个标准中”并非如此
Anton K

@AntonK也许是C ++ 2017?
亚历山德罗·贾科普森

6
@AlessandroJacopson酷,它似乎包含在C ++ 17中-zh.cppreference.com/w/cpp/filesystem
Anton K


1

我很惊讶没有人提到Posix中的标准方法

请使用basename / dirname构造。

男人的基名


POSIX功能并非没有缺点。特别是,它们可能会修改您传入的缓冲区(它们确实确实意味着签名basname(char * path)不是basename(const char * path)),而没有执行该实现的实现似乎必须使用静态缓冲区,这会使它们成为线程不安全的(原则上您也可以返回动态分配的结果,但这使您依赖alloc于C ++中尴尬的族函数。
dmckee ---前主持人小猫

-1

在这方面,标准C ++对您没有多大帮助,因为路径名是特定于平台的。您可以手动解析字符串(如glowcoder的回答),使用操作系统工具(例如http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx),或者可能是最好的方法是,您可以使用第三方文件系统库,例如boost :: filesystem。


该标准的C ++ 1z当前正在尝试采用boost文件系统库,因为现在使平台友好性成为一个问题。至少它仍然在MSVC的实验性标头中。
kayleeFrye_onDeck

-6

只需使用以下命令:ExtractFilePath(your_path_file_name)


5
我相信这是Delphi方法,不是C ++中的方法。
伊恩·亨特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.