【问题标题】:get directory from file path c++从文件路径c ++获取目录
【发布时间】:2011-12-15 10:40:40
【问题描述】:

获取文件所在目录的最简单方法是什么?我正在使用它来查找工作目录。

string filename = "C:\MyDirectory\MyFile.bat" 

在这个例子中,我应该得到“C:\MyDirectory”。

【问题讨论】:

  • 讨厌:这是一个狭窄的 STL 字符串吗?您应该使用 Unicode 字符串来处理 Windows 上的所有文件。
  • @Rup:真的吗?查找'/' 和'\' 时,编码是否重要?只要您不将字符串解释为 ASCII/Latin1/任何错误的假设
  • @sehe 不,当然,如果字符串是 UTF-8,那么您将不会遇到国际化等问题,或者有人向您提供带有日文名称的文件。但只有 UTF-8,当其他一切都使用 UTF-16 时,使用 UTF-8 毫无意义 - 可能包括你首先从哪里获得字符串。
  • @Rup:所以我们知道你更喜欢 UTF16。供您参考,Windows 将文件名视为 UTF-16 字符的 不透明 数组。另请注意,UTF-16 仍然是一种可变长度的字符编码;它实际上并没有比 UTF-8 买多少。如果您为了实现的简单性而争论 UCS-2(固定长度字符),我会理解的,但话说回来,Windows 还是将其视为 UCS-16
  • 为什么要重新发明轮子,亲爱的同事们?使用由可能知道自己在做什么的人测试和编写的库。

标签: c++ visual-c++


【解决方案1】:

初始化不正确,需要转义反斜杠:

string filename = "C:\\MyDirectory\\MyFile.bat";

提取目录(如果存在):

string directory;
const size_t last_slash_idx = filename.rfind('\\');
if (std::string::npos != last_slash_idx)
{
    directory = filename.substr(0, last_slash_idx);
}

【讨论】:

  • 这只是部分的答案,即'在这个例子中,我应该得到......'。要获得正确的解决方案,应使用路径处理库或操作系统调用。
  • 如果文件名(合法地)使用 forward 斜杠则失败。如果文件名是相对的,也无法获取(绝对)目录。还依赖于正确设置编码。当有 Offirmo 的(便携式)Boost 解决方案时,我不会将此标记为“正确”。
【解决方案2】:

又快又脏:

请注意,您必须还查找/,因为它在 Windows 上是允许的替代路径分隔符

#include <string>
#include <iostream>

std::string dirnameOf(const std::string& fname)
{
     size_t pos = fname.find_last_of("\\/");
     return (std::string::npos == pos)
         ? ""
         : fname.substr(0, pos);
}

int main(int argc, const char *argv[])
{
     const std::string fname = "C:\\MyDirectory\\MyFile.bat";

     std::cout << dirnameOf(fname) << std::endl;
}

【讨论】:

    【解决方案3】:

    使用Boost.filesystemparent_path() 函数。

    例如。参数 c:/foo/bar => c:/foo

    更多示例:path decomposition table 和教程here。

    【讨论】:

    • 不是每个人都使用 boost。
    • IIANM,当路径是仅文件名时,这不起作用(即您得到一个空路径)。
    【解决方案4】:

    MFC方式;

    #include <afx.h>
    
    CString GetContainingFolder(CString &file)
    {
        CFileFind fileFind;
        fileFind.FindFile(file);
        fileFind.FindNextFile();
        return fileFind.GetRoot();
    }
    

    或者,甚至更简单

    CString path(L"C:\\my\\path\\document.txt");
    path.Truncate(path.ReverseFind('\\'));
    

    【讨论】:

    【解决方案5】:

    C++17 提供std::filesystem::path。它可能在 C++11 中可用;与 -lstdc++fs 链接。注意该函数不验证路径是否存在;使用 std::filesystem::status 确定文件类型(可能是 filetype::notfound)

    【讨论】:

    • 如果一个人使用 c++17 的话,答案很好。据我所知,这就是它最终被采用的地方。
    【解决方案6】:

    由于问题很旧,但我想添加一个答案,以便对其他人有所帮助。
    在 Visual c++ 中,您也可以使用 CString 或 char 数组

    CString filename = _T("C:\\MyDirectory\\MyFile.bat");  
    PathRemoveFileSpec(filename); 
    

    输出:

    C:\我的目录

    在您的头文件中包含Shlwapi.h。

    MSDN LINK在这里你可以查看示例。

    【讨论】:

    • 此代码无法编译。检查 Andrew Kozlov 的答案
    • 很多 c++ 在没有 CString 的系统上。
    【解决方案7】:

    您可以使用 stdlib.h 头文件中提供的 _spliltpath 函数。请参考此链接。

    http://msdn.microsoft.com/en-us/library/aa273364%28v=VS.60%29.aspx

    【讨论】:

    • 鉴于缺少类似 C# 的 dirname 函数,这绝对是最好的方法,因为它不依赖于路径的格式。
    【解决方案8】:

    一个非常简单的跨平台解决方案(改编自this example for string::find_last_of):

    std::string GetDirectory (const std::string& path)
    {
        size_t found = path.find_last_of("/\\");
        return(path.substr(0, found));
    }
    

    这适用于斜杠可以是向后或向前(或混合)的两种情况,因为它只查找字符串 path 中任何一个的最后一次出现。

    但是,我个人的偏好是使用 Boost::Filesystem 库来处理这样的操作。一个例子:

    std::string GetDirectory (const std::string& path)
    {
        boost::filesystem::path p(path);
        return(p.parent_path().string());
    }
    

    虽然,如果从字符串中获取目录路径是您需要的唯一功能,那么 Boost 可能有点矫枉过正(特别是因为 Boost::Filesystem 是为数不多的 Boost 库之一,它不是仅头文件)。但是,AFIK、Boost::Filesystem 已被批准包含在 TR2 标准中,但可能要到 C++14 或 C++17 标准(可能是后者,基于this answer)才能完全可用,所以根据您的编译器(以及当您阅读本文时),您甚至可能不再需要单独编译它们,因为它们可能已经包含在您的系统中。例如,Visual Studio 2012 已经可以使用一些 TR2 文件系统组件(根据this post),虽然我还没有尝试过,因为我还在使用 Visual Studio 2010...

    【讨论】:

      【解决方案9】:

      从 C++17 开始你可以使用std::filesystem::parent_path:

      #include <filesystem>
      #include <iostream>
      
      int main() {
          std::string filename = "C:\\MyDirectory\\MyFile.bat";
          std::string directory = std::filesystem::path(filename).parent_path().u8string();
          std::cout << directory << std::endl;
      }
      

      【讨论】:

        【解决方案10】:

        这是正确的 winapi 解决方案:

        CString csFolder = _T("c:\temp\file.ext");
        PathRemoveFileSpec(csFolder.GetBuffer(0));
        csFolder.ReleaseBuffer(-1);
        

        【讨论】:

        • "此函数已弃用。我们建议使用 PathCchRemoveFileSpec 函数代替它。"否则这是正确的答案,所以我+1
        • OP 没有提到 winapi。
        【解决方案11】:

        甲壳虫之道)

        #include<tchar.h>
        
        int GetDir(TCHAR *fullPath, TCHAR *dir) {
            const int buffSize = 1024;
        
            TCHAR buff[buffSize] = {0};
            int buffCounter = 0;
            int dirSymbolCounter = 0;
        
            for (int i = 0; i < _tcslen(fullPath); i++) {
                if (fullPath[i] != L'\\') {
                    if (buffCounter < buffSize) buff[buffCounter++] = fullPath[i];
                    else return -1;
                } else {
                    for (int i2 = 0; i2 < buffCounter; i2++) {
                        dir[dirSymbolCounter++] = buff[i2];
                        buff[i2] = 0;
                    }
        
                    dir[dirSymbolCounter++] = fullPath[i];
                    buffCounter = 0;
                }
            }
        
            return dirSymbolCounter;
        }
        

        使用:

        TCHAR *path = L"C:\\Windows\\System32\\cmd.exe";
        TCHAR  dir[1024] = {0};
        
        GetDir(path, dir);
        wprintf(L"%s\n%s\n", path, dir);
        

        【讨论】:

          【解决方案12】:

          您可以简单地搜索最后一个“\”,然后剪切字符串:

          string filePath = "C:\MyDirectory\MyFile.bat" 
          size_t slash = filePath.find_last_of("\");
          string dirPath = (slash != std::string::npos) ? filePath.substr(0, slash) : filePath;
          

          确保在 Linux 中搜索“/”而不是“\”:

          size_t slash = filePath.find_last_of("/");

          【讨论】:

            【解决方案13】:

            如果你可以访问 Qt,你也可以这样做:

            std::string getDirectory(const std::string & file_path)
            {
               return QFileInfo(QString(file_path)).absolutePath().toStdString();
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-03-16
              • 1970-01-01
              • 2015-10-29
              • 2010-10-31
              • 2015-04-20
              • 2017-03-05
              相关资源
              最近更新 更多