Проверьте, указан ли полный путь

105

Есть ли способ проверить, является ли указанный путь полным путем? Прямо сейчас я делаю это:

if (template.Contains(":\\")) //full path already given
{
}
else //calculate the path from local assembly
{
}

Но должен быть более элегантный способ проверить это?

HS2D
источник

Ответы:

142

Попробуйте использовать System.IO.Path.IsPathRooted? Он также возвращается trueдля абсолютных путей.

System.IO.Path.IsPathRooted(@"c:\foo"); // true
System.IO.Path.IsPathRooted(@"\foo"); // true
System.IO.Path.IsPathRooted("foo"); // false

System.IO.Path.IsPathRooted(@"c:1\foo"); // surprisingly also true
System.IO.Path.GetFullPath(@"c:1\foo");// returns "[current working directory]\1\foo"
Detaylor
источник
14
Почему второй пример может быть абсолютным путем?
om471987
4
Второй путь не абсолютен, но укоренен. Начальная косая черта указывает на корень системы.
Detaylor
3
@SmirkinGherkin, в чем разница между корневым и абсолютным путем?
Джейсон Аксельсон
1
См. Мой ответ ( stackoverflow.com/a/35046453/704808 ) для альтернативы, которая обеспечивает полный путь, сохраняя при этом следующие преимущества IsPathRooted: избегание доступа к файловой системе или выдача исключений для недопустимого ввода.
weir
1
@daniel, IIRC, он был включен, чтобы показать, что путь не обязательно должен быть допустимым путем для использования IsPathRooted, это, конечно, не было чем-то значительным. GetFullPathЛиния была включена , так что путь оцениваемая можно было наблюдать
detaylor
30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

Вышеупомянутое условие:

  • не требует разрешений файловой системы
  • возвращается falseв большинстве случаев, когда форматpath недопустим (вместо того, чтобы вызывать исключение)
  • возвращается, trueтолько если pathвключает объем

Поэтому в сценариях, подобных предложенному OP, он может быть более подходящим, чем условия в предыдущих ответах. В отличие от вышеуказанного условия:

  • path == System.IO.Path.GetFullPath(path)выдает исключения вместо возврата falseв следующих сценариях:
    • У вызывающего абонента нет необходимых разрешений
    • Системе не удалось получить абсолютный путь
    • путь содержит двоеточие (":"), которое не является частью идентификатора тома
    • Указанный путь, имя файла или оба значения превышают максимальную длину, определенную системой.
  • System.IO.Path.IsPathRooted(path)возвращает, trueесли pathначинается с одного разделителя каталогов.

Наконец, вот метод, который завершает вышеуказанное условие, а также исключает оставшиеся возможные исключения:

public static bool IsFullPath(string path) {
    return !String.IsNullOrWhiteSpace(path)
        && path.IndexOfAny(System.IO.Path.GetInvalidPathChars().ToArray()) == -1
        && Path.IsPathRooted(path)
        && !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal);
}

РЕДАКТИРОВАТЬ: EM0 сделал хороший комментарий и альтернативный ответ, касающийся любопытного случая таких путей, как C:и C:dir. Чтобы решить, как вы можете обрабатывать такие пути, вы можете углубиться в MSDN -> Настольные приложения Windows -> Разработка -> Технологии рабочего стола -> Доступ к данным и хранилище -> Локальные файловые системы - -> Управление файлами -> Об управлении файлами -> Создание, удаление и обслуживание файлов -> Именование файлов, путей и пространств имен -> Полные и относительные пути

Для функций Windows API, которые управляют файлами, имена файлов часто могут относиться к текущему каталогу, в то время как для некоторых API требуется полный путь. Имя файла указывается относительно текущего каталога, если оно не начинается с одного из следующих символов:

  • UNC-имя любого формата, которое всегда начинается с двух символов обратной косой черты ("\"). Для получения дополнительной информации см. Следующий раздел.
  • Обозначение диска с обратной косой чертой, например «C: \» или «d: \».
  • Одиночная обратная косая черта, например, «\ каталог» или «\ file.txt». Это также называется абсолютным путем.

Если имя файла начинается только с обозначения диска, но не с обратной косой черты после двоеточия, оно интерпретируется как относительный путь к текущему каталогу на диске с указанной буквой. Обратите внимание, что текущий каталог может быть или не быть корневым, в зависимости от того, что он был установлен во время последней операции «изменения каталога» на этом диске. Примеры этого формата следующие:

  • «C: tmp.txt» относится к файлу с именем «tmp.txt» в текущем каталоге на диске C.
  • «C: tempdir \ tmp.txt» относится к файлу в подкаталоге текущего каталога на диске C.

[...]

плотина
источник
3
Мне нравится, что это не выбрасывает недопустимые пути, но возвращает true для таких путей, как «C:» и «C: dir», которые разрешаются GetFullPath с использованием текущего каталога (поэтому они не являются абсолютными). Отправил ответ, который возвращает false для них.
EM0
@ EM0 - Спасибо! Ты только что научил меня чему-то. :)
водослив
15

Пытаться

System.IO.Path.IsPathRooted(template)

Работает как для UNC-путей, так и для локальных.

Например

Path.IsPathRooted(@"\\MyServer\MyShare\MyDirectory")  // returns true
Path.IsPathRooted(@"C:\\MyDirectory")  // returns true
Джо
источник
13

Старый вопрос, но еще один применимый ответ. Если вам нужно убедиться, что том включен в локальный путь, вы можете использовать System.IO.Path.GetFullPath () следующим образом:

if (template == System.IO.Path.GetFullPath(template))
{
    ; //template is full path including volume or full UNC path
}
else
{
    if (useCurrentPathAndVolume)
        template = System.IO.Path.GetFullPath(template);
    else
        template = Assembly.GetExecutingAssembly().Location
}
GreggD
источник
3
Это было то, что мне было нужно, и кажется ближе к исходному вопросу, поскольку IsPathRooted 'возвращает истину для относительных путей (не обязательно абсолютных путей)
биткодер,
GetFullPathобращается к файловой системе и может выдать ряд возможных исключений. См. Мой ответ ( stackoverflow.com/a/35046453/704808 ) для альтернативы, которая по-прежнему обеспечивает полный путь.
weir
11

Основываясь на плотине ответа «s: это не забросить недействительные пути, но и возвращается falseк дорожкам , как„C:“,„C: имя - каталог“и„\ путь“.

public static bool IsFullPath(string path)
{
    if (string.IsNullOrWhiteSpace(path) || path.IndexOfAny(Path.GetInvalidPathChars()) != -1 || !Path.IsPathRooted(path))
        return false;

    string pathRoot = Path.GetPathRoot(path);
    if (pathRoot.Length <= 2 && pathRoot != "/") // Accepts X:\ and \\UNC\PATH, rejects empty string, \ and X:, but accepts / to support Linux
        return false;

    if (pathRoot[0] != '\\' || pathRoot[1] != '\\')
        return true; // Rooted and not a UNC path

    return pathRoot.Trim('\\').IndexOf('\\') != -1; // A UNC server name without a share name (e.g "\\NAME" or "\\NAME\") is invalid
}

Обратите внимание, что это возвращает разные результаты в Windows и Linux, например, «/ path» является абсолютным в Linux, но не в Windows.

Модульный тест:

[Test]
public void IsFullPath()
{
    bool isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); // .NET Framework
    // bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows); // .NET Core

    // These are full paths on Windows, but not on Linux
    TryIsFullPath(@"C:\dir\file.ext", isWindows);
    TryIsFullPath(@"C:\dir\", isWindows);
    TryIsFullPath(@"C:\dir", isWindows);
    TryIsFullPath(@"C:\", isWindows);
    TryIsFullPath(@"\\unc\share\dir\file.ext", isWindows);
    TryIsFullPath(@"\\unc\share", isWindows);

    // These are full paths on Linux, but not on Windows
    TryIsFullPath(@"/some/file", !isWindows);
    TryIsFullPath(@"/dir", !isWindows);
    TryIsFullPath(@"/", !isWindows);

    // Not full paths on either Windows or Linux
    TryIsFullPath(@"file.ext", false);
    TryIsFullPath(@"dir\file.ext", false);
    TryIsFullPath(@"\dir\file.ext", false);
    TryIsFullPath(@"C:", false);
    TryIsFullPath(@"C:dir\file.ext", false);
    TryIsFullPath(@"\dir", false); // An "absolute", but not "full" path

    // Invalid on both Windows and Linux
    TryIsFullPath(null, false, false);
    TryIsFullPath("", false, false);
    TryIsFullPath("   ", false, false);
    TryIsFullPath(@"C:\inval|d", false, false);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname", false, false);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname\", false, !isWindows);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname\\", false, !isWindows);
}

private static void TryIsFullPath(string path, bool expectedIsFull, bool expectedIsValid = true)
{
    Assert.AreEqual(expectedIsFull, PathUtils.IsFullPath(path), "IsFullPath('" + path + "')");

    if (expectedIsFull)
    {
        Assert.AreEqual(path, Path.GetFullPath(path));
    }
    else if (expectedIsValid)
    {
        Assert.AreNotEqual(path, Path.GetFullPath(path));
    }
    else
    {
        Assert.That(() => Path.GetFullPath(path), Throws.Exception);
    }
}
EM0
источник
Хорошая вещь. Я заметил, что msdn.microsoft.com/en-us/library/windows/desktop/… заявляет, что в Windows путь не является относительным, если он начинается с 'Одной обратной косой черты, например, «\ directory» или «\ file .текст". Это также называется абсолютным путем ».
водослив
1
Хорошая точка зрения! Похоже, моя терминология была неправильной. Когда я сказал «абсолютный путь», я действительно думал о том, что М.С. называет «полным путем». Я изменил имя и добавил для этого тестовый пример.
EM0
1
Спасибо за этот ответ, он мне очень помог. Однако обратите внимание, что для UNC-пути, такого как \\ server \, метод возвращает true, но это вызовет исключение, если вы затем вызовете Directory.Exists (path) (System.ArgumentException: 'UNC-путь должен иметь форму \\ server \ share. ')
Карл
2
Приятно видеть, что люди все еще используют это и находят новые крайние случаи. @Carl Обновил код и протестировал его!
EM0
7

Чтобы проверить, полностью ли указан путь (MSDN) :

public static bool IsPathFullyQualified(string path)
{
    var root = Path.GetPathRoot(path);
    return root.StartsWith(@"\\") || root.EndsWith(@"\");
}

Это немного проще, чем то, что уже было предложено, и по-прежнему возвращает false для путей, относящихся к диску, например C:foo. Его логика основана непосредственно на определении MSDN «полностью квалифицированный», и я не нашел никаких примеров, на которых он ведет себя неправильно.


Интересно, однако, что в .NET Core 2.1 появился новый метод, Path.IsPathFullyQualifiedиспользующий внутренний метод.PathInternal.IsPartiallyQualified (точное местоположение ссылки по состоянию на 17 апреля 2018 г.).

Для потомков и лучшей самодостаточности этого поста, вот реализация последнего для справки:

internal static bool IsPartiallyQualified(ReadOnlySpan<char> path)
{
    if (path.Length < 2)
    {
        // It isn't fixed, it must be relative.  There is no way to specify a fixed
        // path with one character (or less).
        return true;
    }

    if (IsDirectorySeparator(path[0]))
    {
        // There is no valid way to specify a relative path with two initial slashes or
        // \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\
        return !(path[1] == '?' || IsDirectorySeparator(path[1]));
    }

    // The only way to specify a fixed path that doesn't begin with two slashes
    // is the drive, colon, slash format- i.e. C:\
    return !((path.Length >= 3)
        && (path[1] == VolumeSeparatorChar)
        && IsDirectorySeparator(path[2])
        // To match old behavior we'll check the drive character for validity as the path is technically
        // not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream.
        && IsValidDriveChar(path[0]));
}
Уильям
источник
4

Это решение, которое я использую

public static bool IsFullPath(string path)
{
    try
    {
        return Path.GetFullPath(path) == path;
    }
    catch
    {
        return false;
    }
}

Это работает следующим образом:

IsFullPath(@"c:\foo"); // true
IsFullPath(@"C:\foo"); // true
IsFullPath(@"c:\foo\"); // true
IsFullPath(@"c:/foo"); // false
IsFullPath(@"\foo"); // false
IsFullPath(@"foo"); // false
IsFullPath(@"c:1\foo\"); // false
Михаил Сенютович
источник
Очень интересно! Например, он хрупкий, он должен соответствовать типам косой черты, но это многообещающе.
Николас Петерсен
Он возвращает неверные результаты для следующих путей: C:\foo\..\fooилиC:\foo\.\.\.
sergtk
1

Вызовите следующую функцию:

Path.IsPathFullyQualified(@"c:\foo")

Документ MSDN: метод Path.IsPathFullyQualified

Полезная цитата из документа MSDN:

Этот метод обрабатывает пути, в которых используется альтернативный разделитель каталогов. Часто ошибочно полагать, что корневые пути ( IsPathRooted (String) ) не относительны. Например, «C: a» относится к диску, то есть разрешается относительно текущего каталога для C: (корневого, но относительного). «C: \ a» является корневым, а не относительным, то есть текущий каталог не используется для изменения пути.

Sergtk
источник
0

Я не совсем уверен, что вы подразумеваете под полным путем (хотя предполагая, что из примера вы имеете в виду не относительный от корня и далее), ну, вы можете использовать класс Path, чтобы помочь вам в работе с путями физических файловых систем, которые должны охватывать вы на все случаи жизни.

Грант Томас
источник