[英]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:\\direoctry
和foo
。 但是如果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.