I am testing software in C# and must ensure proper behavior (graceful failure) occurs when a program is given an invalid full path. Initially this is trivial,as I give something like "Q:\\fakepath" and since there is no Q drive mounted on the system, the program fails as expected.
However, I would like my test to be robust and want a way to generate a path that is guaranteed to not exist and to not be able to exist. The path must be full since if it doesn't start with a drive letter it will be treated relative to some directory, resulting in no failure.
Some approaches I have though of are to search for local drives that are mounted and then pick a drive letter that does not appear. This would work fine and I might end up using this, but I would prefer a more elegant solution such as using a drive letter that could not possibly exist.
Another (potential) option is to use invalid characters in the path name. However, using invalid characters is not preferred as it actually results in a different failure mode of the program.
So formally: How can I most elegantly generate a full path that is guaranteed not be invalid?
EDIT: The program I am testing will go ahead and create a directory (including parent directories) if it is on a valid drive but in a location that does not already exist. Hence, this path needs to be something that couldn't be created with something like Directory.CreateDirectory(<path>), not just something that doesn't already exist.
One method would be to use the Windows API to create a temporary folder. This might sound counterintuitive, but now you have a known empty folder, any path you specify inside it is guaranteed to not exist. For example:
//From https://stackoverflow.com/a/278457/1663001:
public string GetTemporaryDirectory()
{
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
return tempDirectory;
}
public string GetNonexistantPath()
{
return Path.Combine(GetTemporaryDirectory(), "no-such-file");
}
One way to get a guaranteed invalid folder path is have a file that exists with the same name as part of the directory path.
public string Example()
{
string filePath = Path.GetTempFileName(); //Creates a uniquely named, zero-byte temporary file on disk.
var invalidDirectoryPath = Path.Combine(filePath, "CanNotExist");
Directory.CreateDirectory(invalidDirectoryPath); //throws a IOException
}
You could try using one of the reserved words, for instance C:\NUL (case-sensitive). Trying to create such directory will cause a DirectoryNotFoundException. More details here.
You can use some really long path (say a thousand characters). Your program won't probably be able to create it as it is invalid.
You can try this approach. Not sure though it would work or not but a worth try.
use path: Q:\asddsafkdjfkasjdfklahsjfhskdjfladjfhsafjklasdjfkashfkajsdfhasdklfjashdfkljasdhfklajdfajsdfklajsfkjasjfhadkfjasflhakldfjashdfklajsdjfhaksldjfahsdkljadfklajfkjlkajfkljagkjklfdjgklajdkfljgskljgklfjskgjfkljdsgkfsdgsfgsdfgsfggsdfgsfdgsgwesdfgdgjgfadfsfgffgfsdghijklm
Don't bother about counting the total number of letters, you can do the same using http://www.lettercount.com/
The trick is the max length of windows folder can be 260.
Though I tried in on Windows 10 and the max length allowed to me is 247.
Source_MAX_Length_Of_Folder_On_Windows
So, this folder is guaranteed to be never found. Cheers :)
Although, I think the most elegant solution is checking the mounted drives and generate a path afterwards that you have already mentioned and decided to keep it as a last option.
Related
I'm working with files on a case-insensitive (Mac/Windows) file system in C#. But I'd like to find out the real (case-sensitive) name of this file as stored on disk.
I tried making a new FileInfo(filePath) and checking the FullName, but that just gives me back the path I gave it. And the Name property just strips off the directory, again giving me the name as I passed it in, rather than the name of the file actually stored on disk.
I guess I could iterate over all the files in the parent directory, and look for one that best matches the file of interest, but that's going to kill performance. Surely there's an API somewhere that will do this efficiently?
In my test this gives the name as written on disk
var x = Directory.GetFiles(#"E:\temp", "TEST.EXE");
Console.WriteLine(x); // => outputs: E:\temp\test.exe
I am trying to retrieve the subdirectories of a path I pass in. It proccess it and gives me half of the subdirectories but for the other half, it returns a "?" when debugging. I do not know what is causing this
Here is what I have:
string root = #"C:\Users\Documents\Meta Consumer";
string[] subDir = Directory.GetDirectories(root);
When Debugging:
1: (good)
2: (good)
3: (good)
.. ..
?: (this is where 14 is)
?: (15 is here)
.. ..
?: ?
I'm not sure the entire goal, if you intend to specifically Search for a specific item or intend to manipulate the Directory at all. One thing that I do see is you haven't specified any additional search for your array. This can be hindered I believe through deep nesting or permission issues.
Resolution One: Ensure that you have valid permission to do recursive searches within the specified directory.
Resolution Two: You can attempt to run a search for all items with a wildcard then force it to search all directories. This may help solve potential deep nesting issues you may encounter.
Resolution Three: Try the below code; see if it solves the issue.
string root = Environment.GetFolderPath(Environment.SpecialFolder.Documents);
string[] subDir = Directories.GetDirectories(root, "*", SearchOption.AllDirectories);
foreach (string s in subDir)
{
Console.WriteLine(s);
}
See if that returns the proper information that it wasn't previously. There are folders located in your Library that though are considered public to the user are still locked as they reside in the User Profile so permissions will be a good check.
Running Visual Studio as an Administrator will also help in your troubleshooting. Also you should see if there are any Inner Exceptions to help identify it as well.
I've been trying out the most of the Enviroment.SpecialFolder enumeration, but I think there isn't any way of what I'd like to accomplish with the enumeration only. Using the string.Substring() method brought me the farest, yet.
I try to get just the system partition path, where windows is actually installed. On machine A it might be C:\, on machine B it might be D:\.
The most sufficent solution, I found so far was
var path = Environment.GetFolderPath(Environment.SpecialFolder.Windows)
.Substring(0, 3);
Is there a better way to do this? Thanks.
To get the drive, use Path.GetPathRoot. See http://msdn.microsoft.com/en-us/library/system.io.path.getpathroot.aspx
var root = Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.Windows));
If you need "disk where Environment.SpecialFolder.Windows" your sample is ok.
You may want to use Path.GetPathRoot instead of Susbstring...
Note that you probably should not write anything to the root drive yourself (if your program is designed to behave nice).
In my application I need to save a file(image,pdf,txt) to a folder.
I need to add as many images or files to my folder.
Suppose I have an image with name "image1", if this already exists
in the folder and if another user trying to add another image with the name
"image1" then my application automatically needs to change imagename to "image2".
So the application should check whether the file exist, if so save the
new image with a different name.
Any help will be appreciated.
Use the File.Exists method to determine the presence of a file.
However, it must be noted that conflict could still occur. For instance, there is a race condition in that the file could potentially be saved by someone else after the call to determine existence, yet before your call to create the file, so you will still need to account for error.
What you might consider is giving each saved (uploaded?) file a unique name, and referencing them in a database - you can use Guid.NewGuid quite reliably in this case.
As for actually saving the file, you have numerous options here: you could use a FileStream, static methods exposed by the File class, or method of the FileUpload control if you're using that. Please clarify your circumstances.
Lastly, depending on there size, and if a database is being used anyway, you might want to consider storing them as binary data in there, then name conflicts may be irrelevant.
Of course, you can check if the file exists with System.IO.File.Exists(...), but I think your requirements might be a bit too optimistic... there are multiple cases which you should consider. Suppose that you have:
upload.extension
upload1.extension
upload01.extension
upload001.extension
The names above suggest that you should have some naming convention, but that naming convention is not going to be universal (unless you want to have a bunch of naming conventions to cover all of those cases). If the user wants to save a file named "upload" and your naming convention states that the file name would be incremented with a digit with no leading numbers, then you would try "upload1" and if that's not available then "upload2" until you find one that's available.
Let's take the simple case with the convention of adding a digit with no leading zeroes:
int i = 0
string fileExtension = ".extension";
string availableFileName = fileName;
while(System.IO.File.Exists(availableFileName+fileExtension))
{
availableFileName = fileName + i;
i++;
}
fileUpload.SaveAs(availableFileName+fileExtension);
This would append an integer at the end of the file name until you find a file name that is not duplicated.
You can do like...
if (System.IO.File.Exists("Path"))
{
fileUpload1.SaveAs("Path + New FileName");
}
However it would be better if you save the file with appending Current DataTime with the filename. e.g.
fileUpload1.SaveAs("Path + Orginal FileName" + DateTime.Now.ToString("yyyy-MM-dd HHmmtt") + "File Extension";
You should be able to check if the file name already exists using System.IO.File.Exists...
if(System.IO.File.Exists("image1")){
//Use a different name
}
Of course you would need to refine this example to be more flexible for your specific needs.
You can check for a file's existence with the System.IO.File.Exists[MSDN] method. It takes a path string as its argument.
For manipulating the path string should a file exist, take a look at System.IO.Path[MSDN]. It's a great utility for doing just what you need.
I've successfully solved this by having any uploaded files be named by GUID's string representation.
If needed, you can maintain the mapping between GUID's generated file name and the original filename in the DB.
Or just use this:
// Create a temporary file name to use for checking duplicates.
string tempfileName = "";
// Check to see if a file already exists with the
// same name as the file to upload.
if (System.IO.File.Exists(pathToCheck))
{
int counter = 2;
while (System.IO.File.Exists(pathToCheck))
{
// if a file with this name already exists,
// prefix the filename with a number.
tempfileName = counter.ToString() + fileName;
pathToCheck = savePath + tempfileName;
counter ++;
}
fileName = tempfileName;
}
Source: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.fileupload.saveas.aspx
I want to automate a program that reads a file, processes it and then write it to a new file. The problem is that a new file comes in every day, and the contents are similar, the input file and output file names will change daily. The file name will be in the following format: SAPHR_Joiners_20110323. As you can see the first part of the name will be constant but the date will be unique...... How would i be able to do this?
Thanks alot guys
If you want to read the latest file in a folder, you could query the created date, using System.IO.File.GetCreationTime
In code:
string myFile =
Directory.GetFiles(#"C:\Temp")
.OrderBy<String, DateTime>(file => File.GetCreationTime(file))
.First();
However, if you know that the file-name will follow a strict naming convention, then it is better to access the file by generating the file name as other answers suggest.
Can't you just generate the filename dynamically in your program, and then open the corresponding file? So something like this:
string filename = "SAPHR_Joiners_" + DateTime.Now.ToString("yyyyMMdd");
string[] filecontents = File.ReadAllLines( filename );
Use a FileSystemWatcher class to look for new incoming files if you want prompt respone, otherwise just locate the file based on a current date. If you have further problems, let us know.
Back the days of VB6 one technique that still is in use this days is the folder monitoring
You keep checking if a folder has files, every x in x minutes, or in your case, every day at XX hours for example.
and you could create a Service from your program and that will insure that it will run every time (as long as the machine is on) :)
Those days, in VB6, we didn't had so much as you have today, so, for watching a folder for specific file types (or anything at all) *.* you can use the System.IO.FIleSystemWatcher (example in that page), and to process the file, just use System.IO.TextReader for example