Path.Combine이 Path.DirectorySeparatorChar로 시작하는 파일 이름을 올바르게 연결하지 않는 이유는 무엇입니까?
로부터 직접 실행 창 Visual Studio에서 :
> Path.Combine(@"C:\x", "y")
"C:\\x\\y"
> Path.Combine(@"C:\x", @"\y")
"\\y"
둘 다 동일해야합니다.
이전 FileSystemObject.BuildPath ()가 이런 식으로 작동하지 않았습니다 ...
이것은 문서가 말하는 것과 정확히 일치하기 때문에 일종의 철학적 질문입니다 (아마도 Microsoft 만 진정으로 대답 할 수 있음).
"path2에 절대 경로가 포함 된 경우이 방법은 path2를 반환합니다."
다음 은 .NET 소스 의 실제 Combine 방법 입니다. 당신은 호출하는 것을 볼 수 있습니다 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 ()을 호출하십시오.
Path.Combine 메서드에 대한 .NET Reflector 에서 디스 어셈블 된 코드입니다 . 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;
}
이 문제를 해결하고 싶었습니다.
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);
}
또한이 문자열 처리를 수동으로 수행해야한다는 것이 상당히 성가신 것으로 생각되며 그 이유에 관심이 있습니다.
In my opinion this is a bug. The problem is that there are two different types of "absolute" paths. The path "d:\mydir\myfile.txt" is absolute, the path "\mydir\myfile.txt" is also considered to be "absolute" even though it is missing the drive letter. The correct behavior, in my opinion, would be to prepend the drive letter from the first path when the second path starts with the directory separator (and is not a UNC path). I would recommend writing your own helper wrapper function which has the behavior you desire if you need it.
Following Christian Graus' advice in his "Things I Hate about Microsoft" blog titled "Path.Combine is essentially useless.", here is my solution:
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);
}
}
Some advise that the namespaces should collide, ... I went with Pathy, as a slight, and to avoid namespace collision with System.IO.Path.
Edit: Added null parameter checks
From MSDN:
If one of the specified paths is a zero-length string, this method returns the other path. If path2 contains an absolute path, this method returns path2.
In your example, path2 is absolute.
Not knowing the actual details, my guess is that it makes an attempt to join like you might join relative URIs. For example:
urljoin('/some/abs/path', '../other') = '/some/abs/other'
This means that when you join a path with a preceding slash, you are actually joining one base to another, in which case the second gets precedence.
This code should do the trick:
string strFinalPath = string.Empty;
string normalizedFirstPath = Path1.TrimEnd(new char[] { '\\' });
string normalizedSecondPath = Path2.TrimStart(new char[] { '\\' });
strFinalPath = Path.Combine(normalizedFirstPath, normalizedSecondPath);
return strFinalPath;
Reason:
Your second URL is considered an absolute path, The Combine method will only return the last path if the last path is an absolute path.
Solution: Just remove the starting slash / of your second Path (/SecondPath to SecondPath). Then it works as you excepted.
This actually makes sense, in some way, considering how (relative) paths are treated usually:
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
The real question is: Why are paths, which start with "\", considered "rooted"? This was new to me too, but it works that way on Windows:
new FileInfo("\windows"); // FullName = C:\Windows, Exists = True
new FileInfo("windows"); // FullName = C:\Users\Foo.Bar\Windows, Exists = False
If you want to combine both paths without losing any path you can use this:
?Path.Combine(@"C:\test", @"\test".Substring(0, 1) == @"\" ? @"\test".Substring(1, @"\test".Length - 1) : @"\test");
Or with variables:
string Path1 = @"C:\Test";
string Path2 = @"\test";
string FullPath = Path.Combine(Path1, Path2.Substring(0, 1) == @"\" ? Path2.Substring(1, Path2.Length - 1) : Path2);
Both cases return "C:\test\test".
First, I evaluate if Path2 starts with / and if it is true, return Path2 without the first character. Otherwise, return the full Path2.
These two methods should save you from accidentally joining two strings that both have the delimiter in them.
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);
}
This \ means "the root directory of the current drive". In your example it means the "test" folder in the current drive's root directory. So, this can be equal to "c:\test".
Remove the starting slash ('\') in the second parameter (path2) of Path.Combine.
I used aggregate function to force paths combine as below:
public class MyPath
{
public static string ForceCombine(params string[] paths)
{
return paths.Aggregate((x, y) => Path.Combine(x, y.TrimStart('\\')));
}
}
'Programming' 카테고리의 다른 글
| 알림 시스템 구축 [폐쇄] (0) | 2020.05.25 |
|---|---|
| CountDownLatch는 Java 멀티 스레딩에서 어떻게 사용됩니까? (0) | 2020.05.24 |
| C # 메서드 이름에 "Try"는 언제 사용됩니까? (0) | 2020.05.24 |
| Java SE 8에 페어 또는 튜플이 있습니까? (0) | 2020.05.24 |
| BOM이없는 UTF-8 (0) | 2020.05.24 |