Из Немедленное окно в Visual Studio:
> Path.Combine(@"C:\x", "y")
"C:\\x\\y"
> Path.Combine(@"C:\x", @"\y")
"\\y"
Кажется, что они оба должны быть одинаковыми.
Старый FileSystemObject.BuildPath () так не работал ...
Из Немедленное окно в Visual Studio:
> Path.Combine(@"C:\x", "y")
"C:\\x\\y"
> Path.Combine(@"C:\x", @"\y")
"\\y"
Кажется, что они оба должны быть одинаковыми.
Старый FileSystemObject.BuildPath () так не работал ...
Это своего рода философский вопрос (на который, возможно, действительно может ответить только Microsoft), поскольку он делает именно то, что говорится в документации.
«Если путь2 содержит абсолютный путь, этот метод возвращает путь2».
Вот реальный метод Combine из источника .NET. Вы можете видеть, что он вызывает CombineNoChecks, который затем вызывает IsPathRooted на пути 2 и в таком случае возвращает этот путь:
public static String Combine(String path1, String path2) {
if (path1==null || path2==null)
throw new ArgumentNullException((path1==null) ? "path1" : "path2");
Contract.EndContractBlock();
CheckInvalidPathChars(path1);
CheckInvalidPathChars(path2);
return CombineNoChecks(path1, path2);
}
internal static string CombineNoChecks(string path1, string path2)
{
if (path2.Length == 0)
return path1;
if (path1.Length == 0)
return path2;
if (IsPathRooted(path2))
return path2;
char ch = path1[path1.Length - 1];
if (ch != DirectorySeparatorChar && ch != AltDirectorySeparatorChar &&
ch != VolumeSeparatorChar)
return path1 + DirectorySeparatorCharAsString + path2;
return path1 + path2;
}
Я не знаю, в чем причина. Я предполагаю, что решение состоит в том, чтобы убрать (или обрезать) DirectorySeparatorChar с начала второго пути; возможно, напишите свой собственный метод Combine, который сделает это, а затем вызовет Path.Combine ().
cd (component)
из командной строки. Для меня это звучит разумно.
- person Adrian Ratnapala; 10.02.2014
Path.Combine
на всякий случай, но потом он сломался .. Это так глупо :)
- person sotn; 17.07.2017
Я хотел решить эту проблему:
string sample1 = "configuration/config.xml";
string sample2 = "/configuration/config.xml";
string sample3 = "\\configuration/config.xml";
string dir1 = "c:\\temp";
string dir2 = "c:\\temp\\";
string dir3 = "c:\\temp/";
string path1 = PathCombine(dir1, sample1);
string path2 = PathCombine(dir1, sample2);
string path3 = PathCombine(dir1, sample3);
string path4 = PathCombine(dir2, sample1);
string path5 = PathCombine(dir2, sample2);
string path6 = PathCombine(dir2, sample3);
string path7 = PathCombine(dir3, sample1);
string path8 = PathCombine(dir3, sample2);
string path9 = PathCombine(dir3, sample3);
Конечно, все пути 1–9 должны содержать в конце эквивалентную строку. Вот метод PathCombine, который я придумал:
private string PathCombine(string path1, string path2)
{
if (Path.IsPathRooted(path2))
{
path2 = path2.TrimStart(Path.DirectorySeparatorChar);
path2 = path2.TrimStart(Path.AltDirectorySeparatorChar);
}
return Path.Combine(path1, path2);
}
Я также думаю, что это довольно раздражает, что эту обработку строки приходится выполнять вручную, и меня бы интересовала причина этого.
Это дизассемблированный код из .NET Reflector для метода Path.Combine. Проверьте функцию IsPathRooted. Если второй путь является корневым (начинается с DirectorySeparatorChar), вернуть второй путь как есть.
public static string Combine(string path1, string path2)
{
if ((path1 == null) || (path2 == null))
{
throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
}
CheckInvalidPathChars(path1);
CheckInvalidPathChars(path2);
if (path2.Length == 0)
{
return path1;
}
if (path1.Length == 0)
{
return path2;
}
if (IsPathRooted(path2))
{
return path2;
}
char ch = path1[path1.Length - 1];
if (((ch != DirectorySeparatorChar) &&
(ch != AltDirectorySeparatorChar)) &&
(ch != VolumeSeparatorChar))
{
return (path1 + DirectorySeparatorChar + path2);
}
return (path1 + path2);
}
public static bool IsPathRooted(string path)
{
if (path != null)
{
CheckInvalidPathChars(path);
int length = path.Length;
if (
(
(length >= 1) &&
(
(path[0] == DirectorySeparatorChar) ||
(path[0] == AltDirectorySeparatorChar)
)
)
||
((length >= 2) &&
(path[1] == VolumeSeparatorChar))
)
{
return true;
}
}
return false;
}
На мой взгляд это ошибка. Проблема в том, что существует два разных типа «абсолютных» путей. Путь «d: \ mydir \ myfile.txt» является абсолютным, путь «\ mydir \ myfile.txt» также считается «абсолютным», даже если в нем отсутствует буква диска. На мой взгляд, правильным поведением будет добавление буквы диска к первому пути, когда второй путь начинается с разделителя каталогов (и не является UNC-путем). Я бы порекомендовал написать свою собственную вспомогательную функцию-оболочку, которая будет иметь желаемое поведение, если вам это нужно.
Path.Combine
) и языком C #.
- person Grault; 02.09.2016
Из MSDN:
Если один из указанных путей является строкой нулевой длины, этот метод возвращает другой путь. Если путь2 содержит абсолютный путь, этот метод возвращает путь2.
В вашем примере path2 является абсолютным.
Следуя совету Кристиана Грауса в его блоге "Что я ненавижу в Microsoft" под названием «Путь. Комбинировать практически бесполезно. ", вот мое решение:
public static class Pathy
{
public static string Combine(string path1, string path2)
{
if (path1 == null) return path2
else if (path2 == null) return path1
else return path1.Trim().TrimEnd(System.IO.Path.DirectorySeparatorChar)
+ System.IO.Path.DirectorySeparatorChar
+ path2.Trim().TrimStart(System.IO.Path.DirectorySeparatorChar);
}
public static string Combine(string path1, string path2, string path3)
{
return Combine(Combine(path1, path2), path3);
}
}
Некоторые советуют, что пространства имен должны конфликтовать, ... Я пошел с Pathy
, как небольшой, и чтобы избежать столкновения пространств имен с System.IO.Path
.
Изменить: добавлены проверки нулевого параметра.
Этот код должен помочь:
string strFinalPath = string.Empty;
string normalizedFirstPath = Path1.TrimEnd(new char[] { '\\' });
string normalizedSecondPath = Path2.TrimStart(new char[] { '\\' });
strFinalPath = Path.Combine(normalizedFirstPath, normalizedSecondPath);
return strFinalPath;
Не зная фактических деталей, я предполагаю, что он пытается присоединиться, как если бы вы могли присоединиться к относительным URI. Например:
urljoin('/some/abs/path', '../other') = '/some/abs/other'
Это означает, что когда вы присоединяетесь к пути с предыдущей косой чертой, вы фактически присоединяете одну базу к другой, и в этом случае вторая получает приоритет.
Причина:
Ваш второй URL-адрес считается абсолютным путем. Метод Combine
вернет только последний путь, если последний путь является абсолютным путем.
Решение: просто удалите начальную косую черту /
второго пути (от /SecondPath
до SecondPath
). Тогда это работает так, как вы исключили.
Это действительно имеет смысл, учитывая, как обычно обрабатываются (относительные) пути:
string GetFullPath(string path)
{
string baseDir = @"C:\Users\Foo.Bar";
return Path.Combine(baseDir, path);
}
// Get full path for RELATIVE file path
GetFullPath("file.txt"); // = C:\Users\Foo.Bar\file.txt
// Get full path for ROOTED file path
GetFullPath(@"C:\Temp\file.txt"); // = C:\Temp\file.txt
Настоящий вопрос: почему пути, начинающиеся с "\"
, считаются «корневыми»? Для меня это тоже было ново, но так работает на Windows:
new FileInfo("\windows"); // FullName = C:\Windows, Exists = True
new FileInfo("windows"); // FullName = C:\Users\Foo.Bar\Windows, Exists = False
Я использовал агрегатную функцию, чтобы объединить пути, как показано ниже:
public class MyPath
{
public static string ForceCombine(params string[] paths)
{
return paths.Aggregate((x, y) => Path.Combine(x, y.TrimStart('\\')));
}
}
Если вы хотите объединить оба пути без потери пути, вы можете использовать это:
?Path.Combine(@"C:\test", @"\test".Substring(0, 1) == @"\" ? @"\test".Substring(1, @"\test".Length - 1) : @"\test");
Или с переменными:
string Path1 = @"C:\Test";
string Path2 = @"\test";
string FullPath = Path.Combine(Path1, Path2.IsRooted() ? Path2.Substring(1, Path2.Length - 1) : Path2);
В обоих случаях возвращается «C: \ test \ test».
Сначала я оцениваю, начинается ли Path2 с /, и если это правда, возвращаю Path2 без первого символа. В противном случае верните полный путь 2.
== @"\"
вызовом Path.IsRooted()
, поскольку "\"
- не единственный персонаж, который нужно учитывать.
- person rumblefx0; 15.11.2016
Удалите начальную косую черту ('\') во втором параметре (path2) Path.Combine.
Эти два метода должны уберечь вас от случайного соединения двух строк, в каждой из которых есть разделитель.
public static string Combine(string x, string y, char delimiter) {
return $"{ x.TrimEnd(delimiter) }{ delimiter }{ y.TrimStart(delimiter) }";
}
public static string Combine(string[] xs, char delimiter) {
if (xs.Length < 1) return string.Empty;
if (xs.Length == 1) return xs[0];
var x = Combine(xs[0], xs[1], delimiter);
if (xs.Length == 2) return x;
var ys = new List<string>();
ys.Add(x);
ys.AddRange(xs.Skip(2).ToList());
return Combine(ys.ToArray(), delimiter);
}
Это \ означает "корневой каталог текущего диска". В вашем примере это означает «тестовую» папку в корневом каталоге текущего диска. Таким образом, это может быть равно «c: \ test».
Как упоминал Райан, он делает именно то, что говорится в документации.
Из времен DOS различаются текущий диск и текущий путь. \
- это корневой путь, но для ТЕКУЩЕГО ДИСКА.
Для каждого «диска» есть отдельный «текущий путь». Если вы меняете диск с помощью cd D:
, вы меняете не текущий путь на D:\
, а на: «D: \ something \ was \ the \ last \ path \ accessed \ on \ this \ disk» ...
Итак, в Windows буквальный @"\x"
означает: «ТЕКУЩИЙ ДИСК: \ x». Следовательно, Path.Combine(@"C:\x", @"\y")
имеет в качестве второго параметра корневой путь, а не относительный, хотя и не на известном диске ... И поскольку неизвестно, какой может быть «текущий диск», python возвращает "\\y"
.
>cd C:
>cd \mydironC\apath
>cd D:
>cd \mydironD\bpath
>cd C:
>cd
>C:\mydironC\apath
Path.Combine()
в основном предназначен для обратной совместимости (с существующим поведением). Лучше использоватьPath.Join()
. : В отличие от метода Combine, метод Join не пытается укоренить возвращенный путь. (То есть, если path2 является абсолютным путем, метод Join не отбрасывает path1 и не возвращает path2, как это делает метод Combine.) - person Stajs   schedule 17.09.2019