簡體   English   中英

如何在非托管 C++ 代碼中檢查字符串是否具有有效的文件路徑或目錄路徑格式?

[英]How to check if a string has a valid file path or directory path format in unmanaged C++ code?

我想知道如何檢查(在非托管 Visual C++ 代碼中)字符串是否具有表示文件路徑或文件夾路徑的有效格式。 在這種情況下,物理文件或文件夾路徑本身可能存在也可能不存在。 就我而言,檢查正確的字符串格式是主要目標。 我需要知道一個字符串是否具有作為有效文件路徑的正確格式,或者它沒有? 有很多關於 C# 的文章,但沒有一篇關於非托管 C++ 的文章。 如何在 Visual C++ 中的非托管 C++ 中做到這一點?

唯一 100% 確定的方法是“嘗試”。 您可以編寫代碼來確定簡單的情況,但總會有一些問題需要處理,除非您還找出文件所在的驅動器所在的文件系統,因為 Windows 允許“連接”,這意味着解析整個路徑直到最后一部分。

這樣做要簡單得多:

  std::ifstream test(proposedName); 
  if (!test)
  {
      std::cout << "The file doesn't exist" << std::endl;
  }

如果你真的想要花哨,你可以看看errno以確定它是“無效文件名”還是“文件不存在”。 但總的來說,嘗試再次猜測文件名和路徑的有效性是沒有意義的,因為有太多規則可能適用於您的特定情況,也可能不適用。

如果您有不存在的“中途”目錄,情況會變得更加復雜。 您只需解析路徑並嘗試在途中創建目錄[如果整個過程失敗,則再次刪除它]。 但是,由於您必須處理非規范路徑,這一點變得更加復雜。 c:\\blah\\..\\.\\foo\\..\\bar\\xxx.9\\..\\..\\bleurgh\\papa.txt是有效的文件名嗎? 要解決這個問題,您必須首先規范化名稱。

PathCanonicalize或它的朋友會對此有所幫助。 但它仍然充滿了很難解決的令人討厭的復雜位。

當然,你可以嘗試編寫一個正則表達式或其他東西來捕捉簡單的情況,但你仍然會遇到難以弄清楚的情況。

請注意,在某些情況下,路徑可能看起來有效,但實際上並非如此。 想象一下,我們有這個路徑: c:\\directory\\foo\\bar.txt 現在,這看起來完全有效,我們可能必須在其中創建c:\\direoctryfoo 但是如果c:\\directory\\foo是一個已經存在的文件呢? 您會刪除該文件並在其位置創建一個目錄嗎? 或者您會說它“很好”然后在您嘗試創建目錄時失敗? 我不知道答案,這種復雜性就是為什么我說“唯一確保嘗試的方法” - 其他一切都只是追趕你的尾巴,或者接近正確性。

當然,如果我們將文件權限考慮在內,它會變得更加復雜。

[erenon 提出了一個很好的觀點 - 即使您現在檢查它,在您檢查某些東西和您實際開始使用您的路徑之間,您很可能已經更改了目錄結構,使以前的有效名稱無效 - 反之亦然- 這種問題通常被稱為“TOCTOU”——“檢查時間到使用時間”]

如果您合並了最新版本的 boost,您可以使用 FileSystem 為您完成工作並處理所有常見問題(\\ vs \\\\ 等...)。 它還提供了一些其他功能(文件大小、權限等...)

#include <boost/filesystem.hpp>

string filePath= "C:\Temp\myExample.txt";
if (boost::filesystem::exists(filePath))    // does filePath actually exist?
    cout<<"This is a valid file";
else
    cout<<"The file does not exist";

鏈接在這里。

http://www.boost.org/doc/libs/1_47_0/libs/filesystem/v3/doc/tutorial.html

它應該在某個時候在官方 C++ 中,完整的細節在這里。

http://en.cppreference.com/w/cpp/experimental/fs

希望有所幫助,

我認為 Mats Petersson 的回答描述了真實的答案。 我想指出一個常見的錯誤。 假設有以下函數:

bool fileExists(const char* fileName)
{
  std::ifstream test(fileName); 
  return (test) ? true : false;
}

然后以這種方式使用它:

if (fileExists(myFile))
{
  // assume myFile is a valid file
  // WRONG!
}

這里有一個巨大的競爭條件。 myFile在檢查之后但在使用之前可能會變得無效。 確保它確實存在的唯一方法是打開它並保留文件句柄。

這對我有用:

    // Converts "Foo/blah/blee/..\..\../xxx", for example, to "[default drive]:/[default dir]/xxx". The path does not need to exist.

    #include <windows.h>
    #include <stdio.h>

    int main (
        int             argc,
        char * *        argv) {

        if (argc != 2) {
            ::fprintf (stderr, "*** Expected: (arbitrary Windows file path)\n");
            return 1;
        }

        char            result[MAX_PATH+1];
        int             length = ::GetFullPathNameA( argv[1], MAX_PATH, result, NULL);
        if (!length) {
            ::fprintf(stderr, "*** Cannot convert '%s' to a canonical path\n", argv[1]);
            return 2;
        }
        else  {
            result[length] = '\0';
            char *      c = &result[0];
            do  if (*c == '\\') *c = '/';
            while (*++c);
            ::printf("%s\n", result);
            return 0;
        }
    }

無需創建任何文件。 無需Boost。 您可以省略結果的打印,並根據需要返回錯誤/成功狀態。 (我的第一條建議答案!)(我認為)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM