Why does a DirectoryInfo not provide a unified way to get the qualified name for a folder.
In this example:
class Program
{
static void Main(string[] args)
{
System.IO.DirectoryInfo DirInfo = new System.IO.DirectoryInfo(#"C:\TEMP\");
Console.WriteLine(DirInfo.FullName);
System.IO.DirectoryInfo DirInfo2 = new System.IO.DirectoryInfo(#"C:\TEMP");
Console.WriteLine(DirInfo2.FullName);
Console.ReadLine();
}
}
Regardless if the directory actually exists, the FullName just reflects the userinput into the object, but you can't be certain you get a path with a "\" in the end.
In the MSDN documentation there is mentioned a inheritance from FileSystemInfo, where there is the possibility to retrieve the FQN by the property FullPath, but I can't seem to access it from an instance of DirectoryInfo.
Is there maybe a trick, or another method / field to get to be sure that the path always have the same format?
There's no way or method to get the trailing backslash if it's not there. It's completely optional, but it also shouldn't make a difference for your program if it's there or not. But if you want to ensure it:
char[] blackslashes = {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
string dirPath = #"C:\TEMP";
if (!blackslashes.Contains(dirPath.Last()))
dirPath += "\\";
System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(dirPath);
I am not sure if i did understood your question correct ... but to get it unified, just use eg. a Sanitize method.
Example to always remove tailing backslash:
public string SanitizePath(string s) => s.TrimEnd('/', '\\');
Example to always add tailing backslash:
public string SanitizePath(string s) => s[s.Length - 1] == '/' || s[s.Length - 1] == '\\' ? s : String.Concat(s, '\\');
However, if the problem is invalid paths due to that inconsistency, chances are that you use String.Concat to build the full path.
You always should use Path.Combine for combining a path information as that should provide the proper output.
Related
private void CommandMethod(object parameter)
{
string path = #"C:\Users\yu_in\Desktop";
Teststring = Environment.CurrentDirectory;
DirectoryInfo fi = new DirectoryInfo(path);
Teststring2 = fi.FullName;
}
I Can't Understand why
Teststring2 = "C:\Users\yu_in\source\repos\TestApplication\TestApplication\bin\x64\Debug\net5.0-windows\C:\Users\yu_in\Desktop"
why result add Environment.CurrentDirectory ?
There is quite literally more to this question than meets the eye :)
Your path has an additional, invisible, unicode character at the beginning of it:
U+202A (The actual text in your code is: #"[U+202A]C:\Users\yu_in\Desktop"). This is making your path invalid, so the constructor of DirectoryInfo is attempting to use your provided path as a local path.
Instead of this: #"C:\Users\yu_in\Desktop",
use this : #"C:\Users\yu_in\Desktop". I know both paths look the same, but only the second one is a valid path.
How do you get the last folder/directory out of user-input regardless of if the input is a path to a folder or a file? This is when the folder/file in question may not exist.
C:\Users\Public\Desktop\workspace\page0320.xml
C:\Users\Public\Desktop\workspace
I'm trying to get out the folder "workspace" out of both examples, even if the folder "workspace" or file "page0320.xml" doesn't exist.
EDIT: Using BrokenGlass's suggestion, I got it to work.
String path = #"C:\Users\Public\Desktop\workspace";
String path2 = #"C:\Users\Public\Desktop\workspace\";
String path3 = #"C:\Users\Public\Desktop\workspace\page0320.xml";
String fileName = path.Split(new char[] { '\\' }).Last<String>().Split(new char[] { '/' }).Last<String>();
if (fileName.Contains(".") == false)
{
path += #"\";
}
path = Path.GetDirectoryName(path);
You can substitute any of the path variables and the output will be:
C:\Users\Public\Desktop\workspace
Of course, this is working under the assuption that files have extensions. Fortunately, that assumption works for my purposes.
Thanks all. Been a long-time lurker and first-time poster. It was really impressive how fast and helpful the responses were :D
use Path.GetDirectoryName :
string path = Path.GetDirectoryName(#"C:\Users\Public\Desktop\workspace\page0320.xml");
string path2 = Path.GetDirectoryName(#"C:\Users\Public\Desktop\workspace\");
Note the trailing backslash in the path though in the second example - otherwise workspace will be interpreted as file name.
I will use DirectoryInfo in this way:
DirectoryInfo dif = new DirectoryInfo(path);
if(dif.Exist == true)
// Now we have a true directory because DirectoryInfo can't be fooled by
// existing file names.
else
// Now we have a file or directory that doesn't exist.
// But what we do with this info? The user input could be anything
// and we cannot assume that is a file or a directory.
// (page0320.xml could be also the name of a directory)
You can use GetFileName after GetDiretoryName from the Path class in the System.IO namespace.
GetDiretoryName will get the path without the filename (C:\Users\Public\Desktop\workspace).
GetFileName then returns the last part of the path as if it is a extensionless file (workspace).
Path.GetFileName(Path.GetDirectoryName(path));
EDIT: the path must have a trailing path separator to make this example work.
If you can make some assumptions then its pretty easy..
Assumption 1: All files will have an extension
Assumption 2: The containing directory will never have an extension
If Not String.IsNullOrEmpty(Path.GetExtension(thePath))
Return Path.GetDirectoryName(thePath)
Else
Return Path.GetFileName(thePath)
End If
Like said before, there's not really a feasible solution but this might also do the trick:
private string GetLastFolder(string path)
{
//split the path into pieces by the \ character
var parts = path.Split(new[] { Path.DirectorySeparatorChar, });
//if the last part has an extension (is a file) return the one before the last
if(Path.HasExtension(path))
return parts[parts.Length - 2];
//if the path has a trailing \ return the one before the last
if(parts.Last() == "")
return parts[parts.Length - 2];
//if none of the above apply, return the last element
return parts.Last();
}
This might not be the cleanest solution but it will work. Hope this helps!
How do I get the folder name from the full path of the application?
This is the file path below,
c:\projects\root\wsdlproj\devlop\beta2\text
Here "text" is the folder name.
How can I get that folder name from this path?
See DirectoryInfo.Name:
string dirName = new DirectoryInfo(#"c:\projects\roott\wsdlproj\devlop\beta2\text").Name;
I think you want to get parent folder name from file path. It is easy to get.
One way is to create a FileInfo type object and use its Directory property.
Example:
FileInfo fInfo = new FileInfo("c:\projects\roott\wsdlproj\devlop\beta2\text\abc.txt");
String dirName = fInfo.Directory.Name;
Try this
var myFolderName = #"c:\projects\roott\wsdlproj\devlop\beta2\text";
var result = Path.GetFileName(myFolderName);
You could use this:
string path = #"c:\projects\roott\wsdlproj\devlop\beta2\text";
string lastDirectory = path.Split(new char[] { System.IO.Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries).Last();
Simply use Path.GetFileName
Here - Extract folder name from the full path of a folder:
string folderName = Path.GetFileName(#"c:\projects\root\wsdlproj\devlop\beta2\text");//Return "text"
Here is some extra - Extract folder name from the full path of a file:
string folderName = Path.GetFileName(Path.GetDirectoryName(#"c:\projects\root\wsdlproj\devlop\beta2\text\GTA.exe"));//Return "text"
I figured there's no way except going into the file system to find out if text.txt is a directory or just a file. If you wanted something simple, maybe you can just use:
s.Substring(s.LastIndexOf(#"\"));
In this case the file which you want to get is stored in the strpath variable:
string strPath = Server.MapPath(Request.ApplicationPath) + "/contents/member/" + strFileName;
Here is an alternative method that worked for me without having to create a DirectoryInfo object. The key point is that GetFileName() works when there is no trailing slash in the path.
var name = Path.GetFileName(path.TrimEnd(Path.DirectorySeparatorChar));
Example:
var list = Directory.EnumerateDirectories(path, "*")
.Select(p => new
{
id = "id_" + p.GetHashCode().ToString("x"),
text = Path.GetFileName(p.TrimEnd(Path.DirectorySeparatorChar)),
icon = "fa fa-folder",
children = true
})
.Distinct()
.OrderBy(p => p.text);
This can also be done like so;
var directoryName = System.IO.Path.GetFileName(#"c:\projects\roott\wsdlproj\devlop\beta2\text");
Based on previous answers (but fixed)
using static System.IO.Path;
var dir = GetFileName(path?.TrimEnd(DirectorySeparatorChar, AltDirectorySeparatorChar));
Explanation of GetFileName from .NET source:
Returns the name and extension parts of the given path. The resulting
string contains the characters of path that follow the last
backslash ("\"), slash ("/"), or colon (":") character in
path. The resulting string is the entire path if path
contains no backslash after removing trailing slashes, slash, or colon characters. The resulting
string is null if path is null.
I have to create an app that drills into a specific drive, reads all file names and replaces illegal SharePoint characters with underscores.
The illegal characters I am referring to are: ~ # % & * {} / \ | : <> ? - ""
Can someone provide either a link to code or code itself on how to do this? I am VERY new to C# and need all the help i can possibly get. I have researched code on recursively drilling through a drive but i am not sure how to put the character replace and the recursive looping together. Please help!
The advice for removing illegal characters is here:
How to remove illegal characters from path and filenames?
You just have to change the character set to your set of characters that you want to remove.
If you have figured out how to recurse the folders, you can get all of the files in each folder with:
var files = System.IO.Directory.EnumerateFiles(currentPath);
and then
foreach (string file in files)
{
System.IO.File.Move(file, ConvertFileName(file));
}
The ConvertFileName method you will write to accept a filename as a string, and return a filename stripped of the bad characters.
Note that, if you are using .NET 3.5, GetFiles() works too. According to MSDN:
The EnumerateFiles and GetFiles
methods differ as follows: When you
use EnumerateFiles, you can start
enumerating the collection of names
before the whole collection is
returned; when you use GetFiles, you
must wait for the whole array of names
to be returned before you can access
the array. Therefore, when you are
working with many files and
directories, EnumerateFiles can be
more efficient.
How to recursively list directories
string path = #"c:\dev";
string searchPattern = "*.*";
string[] dirNameArray = Directory.GetDirectories(path, searchPattern, SearchOption.AllDirectories);
// Or, for better performance:
// (but breaks if you don't have access to a sub directory; see 2nd link below)
IEnumerable<string> dirNameEnumeration = Directory.EnumerateDirectories(path, searchPattern, SearchOption.AllDirectories);
How to: Enumerate Directories and Files
How to recursively list all the files in a directory in C#?
Not really an answer, but consider both of the following:
The following characters are not valid in filenames anyways so you don't have to worry about them: /\:*?"<>|.
Make sure your algorithm handles duplicate names appropriately. For example, My~Project.doc and My#Project.doc would both be renamed to My_Project.doc.
A recursive method to rename files in folders is what you want. Just pass it the root folder and it will call itself for all subfolders found.
private void SharePointSanitize(string _folder)
{
// Process files in the directory
string [] files = Directory.GetFiles(_folder);
foreach(string fileName in files)
{
File.Move(fileName, SharePointRename(fileName));
}
string[] folders = Directory.GetDirectories(_folder);
foreach(string folderName in folders)
{
SharePointSanitize(folderName);
}
}
private string SharePointRename(string _name)
{
string newName = _name;
newName = newName.Replace('~', '');
newName = newName.Replace('#', '');
newName = newName.Replace('%', '');
newName = newName.Replace('&', '');
newName = newName.Replace('*', '');
newName = newName.Replace('{', '');
newName = newName.Replace('}', '');
// .. and so on
return newName;
}
Notes:
You can replace the '' in the SharePointRename() method to whatever character you want to replace with, such as an underscore.
This does not check if two files have similar names like thing~ and thing%
class Program
{
private static Regex _pattern = new Regex("[~#%&*{}/\\|:<>?\"-]+");
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo("C:\\");
RecursivelyRenameFilesIn(di);
}
public static void RecursivelyRenameFilesIn(DirectoryInfo root)
{
foreach (FileInfo fi in root.GetFiles())
if (_pattern.IsMatch(fi.Name))
fi.MoveTo(string.Format("{0}\\{1}", fi.Directory.FullName, Regex.Replace(fi.Name, _pattern.ToString(), "_")));
foreach (DirectoryInfo di in root.GetDirectories())
RecursivelyRenameFilesIn(di);
}
}
Though this will not handle duplicates names as Steven pointed out.
If i have lots of directory names either as literal strings or contained in variables, what is the easiest way of combining these to make a complete path?
I know of Path.Combine but this only takes 2 string parameters, i need a solution that can take any number number of directory parameters.
e.g:
string folder1 = "foo";
string folder2 = "bar";
CreateAPath("C:", folder1, folder2, folder1, folder1, folder2, "MyFile.txt")
Any ideas?
Does C# support unlimited args in methods?
Does C# support unlimited args in methods?
Yes, have a look at the params keyword. Will make it easy to write a function that just calls Path.Combine the appropriate number of times, like this (untested):
string CombinePaths(params string[] parts) {
string result = String.Empty;
foreach (string s in parts) {
result = Path.Combine(result, s);
}
return result;
}
LINQ to the rescue again. The Aggregate extension function can be used to accomplish what you want. Consider this example:
string[] ary = new string[] { "c:\\", "Windows", "System" };
string path = ary.Aggregate((aggregation, val) => Path.Combine(aggregation, val));
Console.WriteLine(path); //outputs c:\Windows\System
I prefer to use DirectoryInfo vs. the static methods on Directory, because I think it's better OO design. Here's a solution with DirectoryInfo + extension methods, that I think is quite nice to use:
public static DirectoryInfo Subdirectory(this DirectoryInfo self, params string[] subdirectoryName)
{
Array.ForEach(
subdirectoryName,
sn => self = new DirectoryInfo(Path.Combine(self.FullName, sn))
);
return self;
}
I don't love the fact that I'm modifying self, but for this short method, I think it's cleaner than making a new variable.
The call site makes up for it, though:
DirectoryInfo di = new DirectoryInfo("C:\\")
.Subdirectory("Windows")
.Subdirectory("System32");
DirectoryInfo di2 = new DirectoryInfo("C:\\")
.Subdirectory("Windows", "System32");
Adding a way to get a FileInfo is left as an exercise (for another SO question!).
Try this one:
public static string CreateDirectoryName(string fileName, params string[] folders)
{
if(folders == null || folders.Length <= 0)
{
return fileName;
}
string directory = string.Empty;
foreach(string folder in folders)
{
directory = System.IO.Path.Combine(directory, folder);
}
directory = System.IO.Path.Combine(directory, fileName);
return directory;
}
The params makes it so that you can append an infinite amount of strings.
Path.Combine does is to make sure that the inputted strings does not begin with or ends with slashes and checks for any invalid characters.