-
Notifications
You must be signed in to change notification settings - Fork 8
/
SafePath.cs
140 lines (120 loc) · 5.85 KB
/
SafePath.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System.Linq;
using System.IO;
using System;
using System.Runtime.InteropServices;
namespace Rampastring.Tools;
/// <summary>
/// Provides safe cross platform Path handling.
/// </summary>
public static class SafePath
{
/// <summary>
/// Safely combines multiple directory paths for all platforms.
/// The first path can be a relative or absolute path.
/// </summary>
/// <param name="paths">Ordered list of directory paths.</param>
/// <returns>The combined directory path of all <paramref name="paths"/>, with trailing separator character and with leading separator character if the path has a root.</returns>
public static string CombineDirectoryPath(params string[] paths)
{
return Combine(true, paths);
}
/// <summary>
/// Safely combines multiple directory paths with a file name for all platforms.
/// The first path can be a relative or absolute path.
/// </summary>
/// <param name="paths">Ordered list of directory paths with a file name.</param>
/// <returns>The combined directory path and file name of all <paramref name="paths"/> with leading separator character if the path has a root.</returns>
public static string CombineFilePath(params string[] paths)
{
return Combine(false, paths);
}
/// <summary>
/// Safely combines multiple directory paths for all platforms.
/// The first path can be a relative or absolute path.
/// </summary>
/// <param name="paths">Ordered list of directory paths.</param>
/// <returns>A <see cref="DirectoryInfo"/> instance representing the combined directory path of all <paramref name="paths"/>.</returns>
public static DirectoryInfo GetDirectory(params string[] paths)
{
return new DirectoryInfo(CombineDirectoryPath(paths));
}
/// <summary>
/// Safely combines multiple directory paths with a file name for all platforms.
/// The first path can be a relative or absolute path.
/// </summary>
/// <param name="paths">Ordered list of directory paths with a file name.</param>
/// <returns>A <see cref="FileInfo"/> instance representing the combined directory path and file name of all <paramref name="paths"/>.</returns>
public static FileInfo GetFile(params string[] paths)
{
return new FileInfo(CombineFilePath(paths));
}
/// <summary>
/// Safely delete a file represented by multiple directory paths with a file name for all platforms.
/// Does not throw an exception if the file or directory path does not exist.
/// </summary>
/// <param name="paths">Ordered list of directory paths with a file name.</param>
public static void DeleteFileIfExists(params string[] paths)
{
var fileInfo = new FileInfo(CombineFilePath(paths));
if (fileInfo.Exists)
fileInfo.Delete();
}
/// <summary>
/// Safely delete a directory represented by multiple directory paths for all platforms.
/// Does not throw an exception if the directory path does not exist.
/// </summary>
/// <param name="recursive">true to remove directories, subdirectories, and files in path; otherwise, false.</param>
/// <param name="paths">Ordered list of directory paths.</param>
public static void DeleteDirectoryIfExists(bool recursive, params string[] paths)
{
var directoryInfo = new DirectoryInfo(CombineFilePath(paths));
if (directoryInfo.Exists)
directoryInfo.Delete(recursive);
}
/// <summary>
/// Safely retrieves the name of a directory represented by multiple directory paths and a file name for all platforms.
/// </summary>
/// <param name="paths">Ordered list of directory paths and a file name.</param>
/// <returns>The name (not path) of the directory a given file resides in.</returns>
public static string GetFileDirectoryName(params string[] paths)
{
var fileInfo = new FileInfo(CombineFilePath(paths));
return fileInfo.DirectoryName;
}
private static string Combine(bool isDirectoryPath, params string[] paths)
{
if (paths is null)
return null;
paths = paths.Where(p => !string.IsNullOrWhiteSpace(p)).ToArray();
if (!paths.Any())
return null;
if (paths.Length == 1)
paths = new[] { paths[0], null };
string combinedPath = paths.Aggregate((x, y) => y is null ? GetPath(x) : Path.Combine(GetPath(x), GetPath(y)))
.TrimStart(Path.DirectorySeparatorChar)
.TrimStart(Path.AltDirectorySeparatorChar)
.TrimEnd(Path.DirectorySeparatorChar)
.TrimEnd(Path.AltDirectorySeparatorChar);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (paths[0].Length > 1 && paths[0][1] == Path.VolumeSeparatorChar)
return FormattableString.Invariant($"{combinedPath}{(isDirectoryPath ? Path.DirectorySeparatorChar : null)}");
return FormattableString.Invariant($"{(Path.IsPathRooted(paths[0]) ? Path.DirectorySeparatorChar : null)}{combinedPath}{(isDirectoryPath ? Path.DirectorySeparatorChar : null)}");
}
return FormattableString.Invariant($"{(Path.IsPathRooted(paths[0]) ? Path.DirectorySeparatorChar : null)}{combinedPath}{(isDirectoryPath ? Path.DirectorySeparatorChar : null)}");
}
private static string GetPath(string path)
{
return FormattableString.Invariant($"{path?
.Replace("///", "/")
.Replace("//", "/")
.Replace('/', Path.DirectorySeparatorChar)
.Replace("\\\\\\", "\\")
.Replace("\\\\", "\\")
.Replace('\\', Path.DirectorySeparatorChar)
.TrimStart(Path.DirectorySeparatorChar)
.TrimStart(Path.AltDirectorySeparatorChar)
.TrimEnd(Path.DirectorySeparatorChar)
.TrimEnd(Path.AltDirectorySeparatorChar)}{Path.DirectorySeparatorChar}");
}
}