I have to validate user input for file path. So far what I have tried is given below in the code. The code works fine for some cases e.g.
C:\ (valid) (my code returns valid)
C:\(valid) (my code returns valid)
C:+space+\ (my code returns valid but I want to take it as invalid)
C:+space+ filename (my code returns valid but I want to take it as invalid)
It should consider "spaces" between and after the "\" as invalid.
public bool FilePathValid(string path)
{
try
{
Path.GetFullPath(path);
Path.GetFileName(path);
return Path.IsPathRooted(path);
}
catch (Exception e)
{
return false;
}
}
NOTE: I only want to try regex when I have no other options because as once said you try to solve your problem with regex and ends up having two.
So you're not interested in actually validating a path nor checking whether a path points to an existing file or directory, you just want to check if a path separator is preceded or followed by a space?
Then do that:
if (path.Contains(#" \") || path.Contains(#"\ "))
{
// do your magic
}
I need to check if the current user has write permissions inside the path. Here an example:
string save_path = #"C:\Windows\somefolder";
string my_dir = Path.DirectorySeparatorChar + "foobar";
//check if specific path are valid
if (!Directory.Exists(save_path)) { return; }
if (Directory.Exists(save_path + my_dir)) { return; }
if (canWriteOnPath(save_path)) {
Directory.CreateDirectory(save_path + my_dir);
} else {
//You are not allowed to save here OR not are launching this application as "administrator"
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
solved in this question:
CurrentUserSecurity cus = new CurrentUserSecurity();
bool flag = cus.HasAccess(new DirectoryInfo(#"C:\Windows"), FileSystemRights.Write);
if (flag) {
//yes create that folder
Directory.CreateDirectory(Path.Combine(save_path, my_dir));
} else {
//NO YOU CANT
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
The robust method would be to Try to create the directory and Catch any resulting exception.
The documentation for Directory.CreateDirectory lists the possible exceptions: IOException, UnauthorizedAccessException, ArgumentException, ArgumentNullException, PathTooLongException, DirectoryNotFoundException.
Although unlikely, it is possible that the permissions changed between your code checking that access is allowed and actually trying to create the directory.
I have a situation where I have to find a path to the first file named my.exe starting from startingdirectory & \mydir\ and go deep as needed.
Actually, IO.Directory.GetFiles is suitable but I need it stop searching after the first file is found like it is possible with FindFirstFile from WinAPI.
VB.NET
Dim findedDirectories() As String = IO.Directory.GetFiles( _
startingdirectory & "\mydir\", "my.exe", IO.SearchOption.AllDirectories)
C#
string[] findedDirectories = IO.Directory.GetFiles( _
startingdirectory + "\\mydir\\", "my.exe", IO.SearchOption.AllDirectories);
Is it possible to stop searching after the first file is found in a way that the result of the function will be a string or an empty string, not a string array? Or is here better way to search for a first file in subdirectories?
A solution like the following one could help:
/// <summary>
/// Searches for the first file matching to searchPattern in the sepcified path.
/// </summary>
/// <param name="path">The path from where to start the search.</param>
/// <param name="searchPattern">The pattern for which files to search for.</param>
/// <returns>Either the complete path including filename of the first file found
/// or string.Empty if no matching file could be found.</returns>
public static string FindFirstFile(string path, string searchPattern)
{
string[] files;
try
{
// Exception could occur due to insufficient permission.
files = Directory.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
}
catch (Exception)
{
return string.Empty;
}
// If matching files have been found, return the first one.
if (files.Length > 0)
{
return files[0];
}
else
{
// Otherwise find all directories.
string[] directories;
try
{
// Exception could occur due to insufficient permission.
directories = Directory.GetDirectories(path);
}
catch (Exception)
{
return string.Empty;
}
// Iterate through each directory and call the method recursivly.
foreach (string directory in directories)
{
string file = FindFirstFile(directory, searchPattern);
// If we found a file, return it (and break the recursion).
if (file != string.Empty)
{
return file;
}
}
}
// If no file was found (neither in this directory nor in the child directories)
// simply return string.Empty.
return string.Empty;
}
I guess the simplest approach would be to organise the recursion into sub-directories yourself with recursive calls to Directory.GetDirectories passing SearchOption.TopDirectoryOnly. In each directory check for the file's existence with File.Exists.
This actually mirrors the way it would be done in Win32 with FindFirstFile. When using FindFirstFile you always need to implement the sub-directory recursion yourself because FindFirstFile has nothing analagous to SearchOption.AllDirectories.
I want to move a directory from one location to another using C# .NET. I used Directory.Move or even DirectoryInfo (with MoveTo) this simple way:
// source is: "C:\Songs\Elvis my Man"
// newLocation is: "C:\Songs\Elvis"
try
{
// Previous command was: Directory.Move(source, newLocation);
DirectoryInfo dir = new DirectoryInfo(source);
dir.MoveTo(newLocation);
}
catch (Exception e)
{
Console.WriteLine("Error: "+ e.Message);
}
But action that's being done (for both cases) is renaming the folder name from 'source' to 'newLocation'
What I expected? that folder "Elvis my man" will be now in "Elvis" folder.
What has happened? "Elvis my man" was changed to "Elvis" (Renamed). If the directory "Elvis" is already exists, it can't change it to "Elvis" (cause he can't make a duplicate names), therefore I get an exception saying that.
What am I doing wrong??
Many thanks!!!
I would advise putting validation around the Move command to ensure that the source location does exists and the destination location doesn't exists.
I've always found it easier to avoid the exceptions than handle them once they do occur.
You'll probably want to include exception handling as well, just in case the access permissions are a problem or a file is open and can't be moved...
Here's some sample code for you:
string sourceDir = #"c:\test";
string destinationDir = #"c:\test1";
try
{
// Ensure the source directory exists
if (Directory.Exists(sourceDir) == true )
{
// Ensure the destination directory doesn't already exist
if (Directory.Exists(destinationDir) == false)
{
// Perform the move
Directory.Move(sourceDir, destinationDir);
}
else
{
// Could provide the user the option to delete the existing directory
// before moving the source directory
}
}
else
{
// Do something about the source directory not existing
}
}
catch (Exception)
{
// TODO: Handle the exception that has been thrown
}
Even though this works in the command line to move a file, when programming you need to provide the full new name.
So you'd need to change newLocation to "C:\Songs\Elvis\Elvis my Man" to make this work.
From MSDN,
This method throws an IOException if, for example, you try to move c:\mydir to c:\public, and c:\public already exists. You must specify "c:\public\mydir" as the destDirName parameter, or specify a new directory name such as "c:\newdir".
It looks like you need to set newLocation to C:\Songs\Elvis\Elvis my man
private void moveDirectory(string fuente,string destino)
{
if (!System.IO.Directory.Exists(destino))
{
System.IO.Directory.CreateDirectory(destino);
}
String[] files = Directory.GetFiles(fuente);
String[] directories = Directory.GetDirectories(fuente);
foreach (string s in files)
{
System.IO.File.Copy(s, Path.Combine(destino,Path.GetFileName(s)), true);
}
foreach(string d in directories)
{
moveDirectory(Path.Combine(fuente, Path.GetFileName(d)), Path.Combine(destino, Path.GetFileName(d)));
}
}
This question already has answers here:
How do I check if a given string is a legal/valid file name under Windows?
(27 answers)
Closed 7 years ago.
Is there a method in the System.IO namespace that checks the validity of a filename?
For example, C:\foo\bar would validate and :"~-* would not
Or a little trickier, X:\foo\bar would validate is there is an X: drive on the system, but wouldn't otherwise.
I suppose I could write such a method myself, but I'm more interested in a built-in one.
Just do;
System.IO.FileInfo fi = null;
try {
fi = new System.IO.FileInfo(fileName);
}
catch (ArgumentException) { }
catch (System.IO.PathTooLongException) { }
catch (NotSupportedException) { }
if (ReferenceEquals(fi, null)) {
// file name is not valid
} else {
// file name is valid... May check for existence by calling fi.Exists.
}
For creating a FileInfo instance the file does not need to exist.
You can get a list of invalid characters from Path.GetInvalidPathChars and GetInvalidFileNameChars as discussed in this question.
As noted by jberger, there some other characters which are not included in the response from this method. For much more details of the windows platform, take a look at Naming Files, Paths and Namespaces on MSDN.
As Micah points out, there is Directory.GetLogicalDrives to get a list of valid drives.
You could make use the System.Uri class. The Uri class isn't just useful for web URLs, it also handles file system paths as well. Use the Uri.TryCreate method to find if the path is rooted then use the IsLoopback property to determine if the Uri references the local machine.
Here is a simple method which determines if a string is a valid, local, and rooted file path.
public bool IsPathValidRootedLocal(String pathString) {
Uri pathUri;
Boolean isValidUri = Uri.TryCreate(pathString, UriKind.Absolute, out pathUri);
return isValidUri && pathUri != null && pathUri.IsLoopback;
}
I am confident this will work.
There are several methods you could use that exist in the System.IO namespace:
Directory.GetLogicalDrives() // Returns an array of strings like "c:\"
Path.GetInvalidFileNameChars() // Returns an array of characters that cannot be used in a file name
Path.GetInvalidPathChars() // Returns an array of characters that cannot be used in a path.
As suggested you could then do this:
bool IsValidFilename(string testName) {
string regexString = "[" + Regex.Escape(Path.GetInvalidPathChars()) + "]";
Regex containsABadCharacter = new Regex(regexString);
if (containsABadCharacter.IsMatch(testName)) {
return false;
}
// Check for drive
string pathRoot = Path.GetPathRoot(testName);
if (Directory.GetLogicalDrives().Contains(pathRoot)) {
// etc
}
// other checks for UNC, drive-path format, etc
return true;
}
Thought I would post a solution I cobbled together from bits of answers I found after searching for a robust solution to the same problem. Hopefully it helps someone else.
using System;
using System.IO;
//..
public static bool ValidateFilePath(string path, bool RequireDirectory, bool IncludeFileName, bool RequireFileName = false)
{
if (string.IsNullOrEmpty(path)) { return false; }
string root = null;
string directory = null;
string filename = null;
try
{
// throw ArgumentException - The path parameter contains invalid characters, is empty, or contains only white spaces.
root = Path.GetPathRoot(path);
// throw ArgumentException - path contains one or more of the invalid characters defined in GetInvalidPathChars.
// -or- String.Empty was passed to path.
directory = Path.GetDirectoryName(path);
// path contains one or more of the invalid characters defined in GetInvalidPathChars
if (IncludeFileName) { filename = Path.GetFileName(path); }
}
catch (ArgumentException)
{
return false;
}
// null if path is null, or an empty string if path does not contain root directory information
if (String.IsNullOrEmpty(root)) { return false; }
// null if path denotes a root directory or is null. Returns String.Empty if path does not contain directory information
if (String.IsNullOrEmpty(directory)) { return false; }
if (RequireFileName)
{
// if the last character of path is a directory or volume separator character, this method returns String.Empty
if (String.IsNullOrEmpty(filename)) { return false; }
// check for illegal chars in filename
if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { return false; }
}
return true;
}
Even if the filename is valid, you may still want to touch it to be sure the user has permission to write.
If you won't be thrashing the disk with hundreds of files in a short period of time, I think creating an empty file is a reasonable approach.
If you really want something lighter, like just checking for invalid chars, then compare your filename against Path.GetInvalidFileNameChars().
Several of the System.IO.Path methods will throw exceptions if the path or filename is invalid:
Path.IsPathRooted()
Path.GetFileName()
http://msdn.microsoft.com/en-us/library/system.io.path_methods.aspx
I've had luck using regular expressions as others have shown.
One thing to keep in mind is that Windows at least prohibits some filenames that otherwise containlegal characters. A few come to mind: com, nul, prn.
I don't have it with me now, but I have a regex that takes these filename into consideration. If you want I can post it, otherwise I'm sure you can find it the same way I did: Google.
-Jay
Use the static GetInvalidFileNameChars method on the Path class in the System.IO namespace to determine what characters are illegal in a file name.
To do so in a path, call the static GetInvalidPathChars method on the same class.
To determine if the root of a path is valid, you would call the static GetPathRoot method on the Path class to get the root, then use the Directory class to determine if it is valid. Then you can validate the rest of the path normally.
Try out this method which would try to cover for all the possible Exceptions scenarios. It would work for almost all the Windows related Paths.
/// <summary>
/// Validate the Path. If path is relative append the path to the project directory by default.
/// </summary>
/// <param name="path">Path to validate</param>
/// <param name="RelativePath">Relative path</param>
/// <param name="Extension">If want to check for File Path</param>
/// <returns></returns>
private static bool ValidateDllPath(ref string path, string RelativePath = "", string Extension = "") {
// Check if it contains any Invalid Characters.
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) {
try {
// If path is relative take %IGXLROOT% as the base directory
if (!Path.IsPathRooted(path)) {
if (string.IsNullOrEmpty(RelativePath)) {
// Exceptions handled by Path.GetFullPath
// ArgumentException path is a zero-length string, contains only white space, or contains one or more of the invalid characters defined in GetInvalidPathChars. -or- The system could not retrieve the absolute path.
//
// SecurityException The caller does not have the required permissions.
//
// ArgumentNullException path is null.
//
// NotSupportedException path contains a colon (":") that is not part of a volume identifier (for example, "c:\").
// PathTooLongException The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.
// RelativePath is not passed so we would take the project path
path = Path.GetFullPath(RelativePath);
} else {
// Make sure the path is relative to the RelativePath and not our project directory
path = Path.Combine(RelativePath, path);
}
}
// Exceptions from FileInfo Constructor:
// System.ArgumentNullException:
// fileName is null.
//
// System.Security.SecurityException:
// The caller does not have the required permission.
//
// System.ArgumentException:
// The file name is empty, contains only white spaces, or contains invalid characters.
//
// System.IO.PathTooLongException:
// The specified path, file name, or both exceed the system-defined maximum
// length. For example, on Windows-based platforms, paths must be less than
// 248 characters, and file names must be less than 260 characters.
//
// System.NotSupportedException:
// fileName contains a colon (:) in the middle of the string.
FileInfo fileInfo = new FileInfo(path);
// Exceptions using FileInfo.Length:
// System.IO.IOException:
// System.IO.FileSystemInfo.Refresh() cannot update the state of the file or
// directory.
//
// System.IO.FileNotFoundException:
// The file does not exist.-or- The Length property is called for a directory.
bool throwEx = fileInfo.Length == -1;
// Exceptions using FileInfo.IsReadOnly:
// System.UnauthorizedAccessException:
// Access to fileName is denied.
// The file described by the current System.IO.FileInfo object is read-only.-or-
// This operation is not supported on the current platform.-or- The caller does
// not have the required permission.
throwEx = fileInfo.IsReadOnly;
if (!string.IsNullOrEmpty(Extension)) {
// Validate the Extension of the file.
if (Path.GetExtension(path).Equals(Extension, StringComparison.InvariantCultureIgnoreCase)) {
// Trim the Library Path
path = path.Trim();
return true;
} else {
return false;
}
} else {
return true;
}
} catch (ArgumentNullException) {
// System.ArgumentNullException:
// fileName is null.
} catch (System.Security.SecurityException) {
// System.Security.SecurityException:
// The caller does not have the required permission.
} catch (ArgumentException) {
// System.ArgumentException:
// The file name is empty, contains only white spaces, or contains invalid characters.
} catch (UnauthorizedAccessException) {
// System.UnauthorizedAccessException:
// Access to fileName is denied.
} catch (PathTooLongException) {
// System.IO.PathTooLongException:
// The specified path, file name, or both exceed the system-defined maximum
// length. For example, on Windows-based platforms, paths must be less than
// 248 characters, and file names must be less than 260 characters.
} catch (NotSupportedException) {
// System.NotSupportedException:
// fileName contains a colon (:) in the middle of the string.
} catch (FileNotFoundException) {
// System.FileNotFoundException
// The exception that is thrown when an attempt to access a file that does not
// exist on disk fails.
} catch (IOException) {
// System.IO.IOException:
// An I/O error occurred while opening the file.
} catch (Exception) {
// Unknown Exception. Might be due to wrong case or nulll checks.
}
} else {
// Path contains invalid characters
}
return false;
}
I don't know of anything out of the box that can just validate all of that for you, however the Path class in .NET can help you out tremendously.
For starters, it has:
char[] invalidChars = Path.GetInvalidFileNameChars(); //returns invalid charachters
or:
Path.GetPathRoot(string); // will return the root.
Probably the bast way is to build a custom method mixing a combination of regex and small look up on your file system (to see the drives, for example)
This will get you the drives on the machine:
System.IO.DriveInfo.GetDrives()
These two methods will get you the bad characters to check:
System.IO.Path.GetInvalidFileNameChars();
System.IO.Path.GetInvalidPathChars();
Think it's too late to answer but... :)
in case of path with volume name you could write something like this:
using System;
using System.Linq;
using System.IO;
// ...
var drives = Environment.GetLogicalDrives();
var invalidChars = Regex.Replace(new string(Path.GetInvalidFileNameChars()), "[\\\\/]", "");
var drive = drives.FirstOrDefault(d => filePath.StartsWith(d));
if (drive != null) {
var fileDirPath = filePath.Substring(drive.Length);
if (0 < fileDirPath.Length) {
if (fileDirPath.IndexOfAny(invalidChars.ToCharArray()) == -1) {
if (Path.Combine(drive, fileDirPath) != drive) {
// path correct and we can proceed
}
}
}
}