Best way to test FileNotFound handling - c#

I'm relatively new to testing and still getting my head around some of the fundamentals. I have a method that I would like to test which basically creates a different file name if the supplied already exists (I've pasted the code below).
I need a way of testing that the method returns a different (but also unique) name if the file already exists. What's the best way of testing this within Visual Studio's unit testing? Is it to create a file as part of the test and then delete it or is there a better way?
public static FileInfo SafeFileName(this FileInfo value)
{
if (value == null) throw new ArgumentNullException("value");
FileInfo fi = value;
//Check the directory exists -if it doesn't create it as we won't move out of this dir
if (!fi.Directory.Exists)
fi.Directory.Create();
//It does so create a new name
int counter = 1;
string pathStub = Path.Combine(fi.Directory.FullName, fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length));
// Keep renaming it until we have a safe filename
while (fi.Exists)
fi = new FileInfo(String.Concat(pathStub, "_", counter++, fi.Extension));
return fi;
}

I think a better would be to use the .Net runtime:
System.IO.Path.GetRandomFileName()
and get rid of the file name generation code all together.
GetRandomFileName

Here are two testing methods (using a Visual Studio unit testing project) for the two scenarios:
// using System.IO;
[TestMethod]
public void WhenFileExists()
{
// Create a file
string existingFilename = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
using (File.Open(existingFilename, FileMode.CreateNew)) { }
// Check its existence
Assert.IsTrue(File.Exists(existingFilename));
// Call method to be tested
string newFilename = DummyCreateFile(existingFilename);
// Check filenames are different
Assert.AreNotEqual<string>(existingFilename, newFilename);
// Check the new file exists
Assert.IsTrue(File.Exists(newFilename));
}
[TestMethod]
public void WhenFileDoesNotExist()
{
// Get a filename but do not create it yet
string existingFilename = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
// Check the file does not exist
Assert.IsFalse(File.Exists(existingFilename));
// Call method to be tested
string newFilename = DummyCreateFile(existingFilename);
// Check the file was created with the filename passed as parameter
Assert.AreEqual<string>(existingFilename, newFilename);
// Check the new file exists
Assert.IsTrue(File.Exists(newFilename));
}
private string DummyCreateFile(string filename)
{
try
{
using (File.Open(filename, FileMode.CreateNew)) { }
return filename;
}
catch
{
string newFilename = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
using (File.Open(newFilename, FileMode.CreateNew)) { }
return newFilename;
}
}
The tested method is slightly changed in that it takes (and returns) a string argument instead of FileInfo for simplicity reasons.

Use File.Exists Method.

Related

Batch renaming files C#

I have a unity project that i need to rename basically all my files in it to contain a - as a way of easily identifying what assetbundle i need to load it from.
I would need to insert a - at the end of the identifier so for example, testtest.png would become test-test.png and so on.
I currently have this (just want to get the identifier from the file name itself for now) however, the first string in temp is always empty with the second one containing the rest of the file name
foreach (string file in Directory.GetFiles(Directory.GetCurrentDirectory()))
{
string name = file.Split('\\').Last();
if (name.StartsWith(args[0]))
{
string[] temp = name.Split(new[]{args[0]},StringSplitOptions.None);
foreach (string s in temp)
{
Console.WriteLine(s);
}
}
}
D:\renamething\bin\Debug>renamething.exe test
.pdb
I tried Regex for it as well however it produced the same result, empty string in the first one, rest of it in the second.
I don't think that would work, especially the args[0]
Try this:
foreach (string file in Directory.GetFiles(Directory.GetCurrentDirectory()))
{
var fileInfo = new FileInfo(file); //Get FileInfo
if (!fileInfo.Name.StartsWith(args[0], StringComparison.OrdinalIgnoreCase)) //If File doesn't start with the specified arguments, don't process
{
continue;
}
//Consider file -> C:/TestFolder/test.png
var directory = fileInfo.DirectoryName;//Gives C:\TestFolder\
var extension = fileInfo.Extension; //gives ".png"
var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name); //Gives "test"
var modifiedFileName = $"{fileName}-test{extension}"; //Gives "test-test.png
var modifiedFullPath = $"{directory}/{modifiedFileName}";// C:\TestFolder\test-test.png
fileInfo.MoveTo(modifiedFullPath);
}
With the code from #Zee (and #Dai from having a second look over), here is what i ended up in the odd chance that anyone else in the future comes here and needs it
public static void Main(string[] args){
foreach(string file in Directory.GetFiles(Directory.GetCurrentDirectory())){
FileInfo fileInfo=new FileInfo(file);
if(fileInfo.Name.StartsWith(args[0])&&fileInfo.Name.EndsWith(".png"){
string[]temp=Regex.Split(fileInfo.Name, #"(?<!^)(?=[A-Z])");
temp[0]+="-";
File.Move(fileInfo.FullName,String.Concat(temp));
}
}
}

Make syntax shorter when using if & else with statements

I'm currently working on a dll library project.
if (!Directory.Exists(MenGinPath))
{
Directory.CreateDirectory(MenGinPath + #"TimedMessages");
File.WriteAllLines(MenGinPath + #"TimedMessages\timedmessages.txt", new string[] { "Seperate each message with a new line" });
}
else if (!File.Exists(MenGinPath + #"TimedMessages\timedmessages.txt"))
{
Directory.CreateDirectory(MenGinPath + #"TimedMessages");
File.WriteAllLines(MenGinPath + #"TimedMessages\timedmessages.txt", new string[] { "Seperate each message with a new line" });
}
As you can see if the statement Directory.Exists is false a specific directory (MenGinPath) will be created. However, if the same path, with another file in addition is false, the second functions will be called.
My question is the following: is there any way to make this shorter?
Because as you can see I'm calling 2 times the same functions:
Directory.CreateDirectory(MenGinPath + #TimedMessages\timedmessages.txt
and
File.WriteAllLines(MenGinPath + #"\TimedMessages\timedmessages.txt"))
Any help would be welcome!!
You don't need to check if directory exists because Directory.CreateDirectory automatically creates the directory if it does not exists and does nothing if the directory already exists.
Also, do not include the filename when creating the directory. Yes, it wont error but just for clarity sake.
Another one is to use Path.Combine instead of hardcoding the path. This will improve readability of your code.
So, here's what I can come up with:
string dir = Path.Combine(MenGinPath, #"Groups\TimesMessages");
string file = Path.Combine(dir, "timedmessages.txt");
// this automatically creates all directories in specified path
// unless it already exists
Directory.CreateDirectory(dir);
//of course, you still need to check if the file exists
if (!File.Exists(file) {
File.WriteAllLines(filePath, new string[] { "Seperate each message with a new line" });
}
/* or if file exists, do your stuff (optional)
* else {
* //do something else? maybe edit the file?
* }
*/
You can make your code shorter given the fact that CreateDirectory does nothing when the directory exists. Moreover do not pullute your code with all that string concatenations to create the path and the file names.
Just do it one time before entering the logic using the appropriate method to create filenames and pathnames (Path.Combine).
string messagePath = Path.Combine(MenGinPath, "TimedMessages");
string fileName = Path.Combine(messagePath, "timedmessages.txt");
// call the create even if it exists. The CreateDirectory checks the fact
// by itself and thus, if you add your own check, you are checking two times.
Directory.CreateDirectory(messagePath);
if (!File.Exists(fileName)
File.WriteAllLines(fileName, new string[] { "Seperate each message with a new line" });
Would something like this work?
string strAppended = string.Empty;
if (!Directory.Exists(MenGinPath))
{
strAppended = MenGinPath + #"Groups\timedmessages.txt";
}
else if (!File.Exists(MenGinPath + #"TimedMessages\timedmessages.txt"))
{
strAppended = MenGinPath + #"TimedMessages\TimedMessages.txt";
}
else
{
return;
}
Directory.CreateDirectory(strAppended);
File.WriteAllLines(strAppended, new string[] { "Seperate each message with a new line" });
I have found that it is a great idea to reuse blocks of code like this instead of hiding them in if statements because it makes code maintenance and debugging easier and less prone to missed bugs.
It seems the only difference between the 2 cases is the path. So just get only this path in your if-else
const string GroupsPath = #"Groups\timedmessages.txt";
const string TimedMessagesTxt = #"TimedMessages\TimedMessages.txt";
string addPath = null;
if (!Directory.Exists(MenGinPath)) {
addPath = GroupsPath;
} else if (!File.Exists(Path.Combine(MenGinPath, TimedMessagesTxt))) {
addPath = TimedMessagesTxt;
}
If (addPath != null) {
Directory.CreateDirectory(Path.Combine(MenGinPath, addPath));
File.WriteAllLines(Path.Combine(MenGinPath, TimedMessagesTxt),
new string[] { "Seperate each message with a new line" });
}
Note: Using Path.Combine instead of string concatenation has the advantage that missig or extra \ are added or removed automatically.

File.Move Not Working, No Error

I'm running into some issues trying to move flat HTML files around on a server.
In short, the process says that it should take whatever file is currently in the newpath (if there is one) and move it to the backup folder. Then take the file in the old path and move it to the new path. Then it checks to see if it was successful (i.e. does the newpath exist) and if it wasn't, it replaces the backup. I've pasted the method below for your viewing pleasure.
public bool MoveContent(string oldPath, string newPath, string backupDirectoryPath, out string backupPath)
{
backupPath = String.Empty;
var oldFilePath = HttpContext.Current.Server.MapPath(oldPath);
var newFilePath = HttpContext.Current.Server.MapPath(newPath);
var newDirectory = Path.GetDirectoryName(newFilePath);
// If the file we're moving doesn't exist, fail.
if (!File.Exists(oldFilePath))
throw new InvalidPathException(oldFilePath);
// If no destination is found, fail.
if (string.IsNullOrWhiteSpace(newDirectory))
throw new InvalidPathException(newFilePath);
if (!Directory.Exists(newDirectory))
Directory.CreateDirectory(newDirectory);
var backupPhysicalPath = String.Empty;
// If there is a file in our destination, back that one up.
if (File.Exists(newFilePath) && !String.IsNullOrWhiteSpace(backupDirectoryPath))
{
var backupFilePath = HttpContext.Current.Server.MapPath(backupDirectoryPath);
var backupDirectory = Path.GetDirectoryName(backupFilePath);
// If the backup destination doesn't exist, fail.
if(string.IsNullOrWhiteSpace(backupDirectory))
throw new InvalidPathException(backupDirectory);
if(!Directory.Exists(backupDirectory))
Directory.CreateDirectory(backupDirectory);
var fileName = Path.GetFileNameWithoutExtension(newFilePath);
var currentDateTime = DateTime.Now.ToString(FileHelpers.TempFileDateFormat);
var fileExtension = Path.GetExtension(newFilePath);
// Example Result: hardware-2015-01-30-08-35-26-475.html
backupPath = backupDirectoryPath.Replace(fileName, fileName + "-" + currentDateTime);
backupPhysicalPath = String.Format("{0}\\{1}-{2}{3}", backupDirectory, fileName, currentDateTime, fileExtension);
// If there is already a file in our backup destination, fail.
if (File.Exists(backupPhysicalPath))
throw new InvalidPathException(backupPhysicalPath);
// Backup the file that currently exists in our new destination.
File.Move(newFilePath, backupPhysicalPath);
}
// Move our file to the new destination.
File.Move(oldFilePath, newFilePath);
// Return false if the new file doesn't exist.
if (!File.Exists(newFilePath))
{
// If we made a backup, return the backup to the original loction, since there's nothing in the destination.
if (!String.IsNullOrWhiteSpace(backupPhysicalPath) && File.Exists(backupPhysicalPath))
{
File.Move(backupPhysicalPath, newFilePath);
}
throw new Exception(String.Format("Failed to move content. OldPath: '{0}'; NewPath: '{1}'; BackupPath: '{2}'", oldFilePath, newFilePath, backupPhysicalPath));
}
return true;
}
Here's an example of the parameters being passed in:
oldPath: "/client/content/en/unpublished/Anpan.html"
newPath: "/client/content/en/Anpan.html"
backupDirectoryPath: "/client/content/en/backups/Anpan.html"
The problem that I'm running into is that sometimes the backup file will be made (it will move from newpath to backuppath), but it won't move from oldpath to newpath.
I've been unable to actually reproduce the issue as it happens so infrequently and without any exceptions being thrown, but the symptoms exist (I can see the files on the filesystem when the client reports the issue) and it's been reported multiple times.
I put some logging around it and wrapped the entire method in a try/catch. It never fails unexpectedly (except when I specifically throw the InvalidPathException). There is nothing in my logs when it happens.
Can anyone help me to diagnose this issue, or tell me if I'm doing something very wrong in my method that would cause the problem?
Thanks so much!

Creating FileInfo - Unexpected Behavior

I am trying to create a file with a FileInfo object and I am getting strange behavior.
Here is the gist of what I am doing -
public void CreateLog()
{
FileInfo LogFile = new FileInfo("");
if (!LogFile.Directory.Exists) { LogFile.Directory.Create(); }
if (!LogFile.Exists) { LogFile.Create(); }
if (LogFile.Length == 0)
{
using (StreamWriter Writer = LogFile.AppendText())
{
Writer.WriteLine("Quotes for " + Instrument.InstrumentID);
Writer.WriteLine("Time,Bid Size,Bid Price,Ask Price,Ask Size");
}
}
}
However, when it checks to see the length of the logfile, it says that the file does not exist (I checked - it does exist).
When I substitute LogFile.Length with the following:
File.ReadAllLines(LogFile.FullName).Length;
Then I get an exception that says that it cannot access the file because something else is already accessing it.
BUT, if I do a Thread.Sleep(500) before I do ReadAllLines, then it seems to work fine.
What am I missing?
LogFile.Create() if you user this function ,you may lock the file, so you can use using ,like this
using(LogFile.Create()){}
after that you can use the file again

If a folder does not exist, create it

I use a FileUploader control in my application. I want to save a file to a specified folder. If this folder does not exist, I want to first create it, and then save my file to this folder. If the folder already exists, then just save the file in it.
How can I do this?
Use System.IO.Directory.CreateDirectory.
According to the official ".NET" docs, you don't need to check if it exists first.
System.io   >   Directory   >   Directory.CreateDirectory
Any and all directories specified in path are created, unless they already exist or unless some part of path is invalid. If the directory already exists, this method does not create a new directory, but it returns a DirectoryInfo object for the existing directory.
        — learn.microsoft.com/dotnet/api/
Use the below code as per How can I create a folder dynamically using the File upload server control?:
string subPath ="ImagesPath"; // Your code goes here
bool exists = System.IO.Directory.Exists(Server.MapPath(subPath));
if(!exists)
System.IO.Directory.CreateDirectory(Server.MapPath(subPath));
Just write this line:
System.IO.Directory.CreateDirectory("my folder");
If the folder does not exist yet, it will be created.
If the folder exists already, the line will be ignored.
Reference: Article about Directory.CreateDirectory at MSDN
Of course, you can also write using System.IO; at the top of the source file and then just write Directory.CreateDirectory("my folder"); every time you want to create a folder.
Directory.CreateDirectory explains how to try and to create the FilePath if it does not exist.
Directory.Exists explains how to check if a FilePath exists. However, you don't need this as CreateDirectory will check it for you.
You can create the path if it doesn't exist yet with a method like the following:
using System.IO;
private void CreateIfMissing(string path)
{
bool folderExists = Directory.Exists(Server.MapPath(path));
if (!folderExists)
Directory.CreateDirectory(Server.MapPath(path));
}
This method will create the folder if it does not exist and do nothing if it exists:
Directory.CreateDirectory(path);
You can use a try/catch clause and check to see if it exist:
try
{
if (!Directory.Exists(path))
{
// Try to create the directory.
DirectoryInfo di = Directory.CreateDirectory(path);
}
}
catch (IOException ioex)
{
Console.WriteLine(ioex.Message);
}
using System.IO
if (!Directory.Exists(yourDirectory))
Directory.CreateDirectory(yourDirectory);
if (!Directory.Exists(Path.GetDirectoryName(fileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
}
The following code is the best line(s) of code I use that will create the directory if not present.
System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath("~/temp/"));
If the directory already exists, this method does not create a new directory, but it returns a DirectoryInfo object for the existing directory. >
Create a new folder, given a parent folder's path:
string pathToNewFolder = System.IO.Path.Combine(parentFolderPath, "NewSubFolder");
DirectoryInfo directory = Directory.CreateDirectory(pathToNewFolder);
// Will create if does not already exist (otherwise will ignore)
path to new folder given
directory information variable so you can continue to manipulate it as you please.
Use this code if the folder is not presented under the image folder or other folders
string subPath = HttpContext.Current.Server.MapPath(#"~/Images/RequisitionBarCode/");
bool exists = System.IO.Directory.Exists(subPath);
if(!exists)
System.IO.Directory.CreateDirectory(subPath);
string path = HttpContext.Current.Server.MapPath(#"~/Images/RequisitionBarCode/" + OrderId + ".png");
Use the below code. I use this code for file copy and creating a new folder.
string fileToCopy = "filelocation\\file_name.txt";
String server = Environment.UserName;
string newLocation = "C:\\Users\\" + server + "\\Pictures\\Tenders\\file_name.txt";
string folderLocation = "C:\\Users\\" + server + "\\Pictures\\Tenders\\";
bool exists = System.IO.Directory.Exists(folderLocation);
if (!exists)
{
System.IO.Directory.CreateDirectory(folderLocation);
if (System.IO.File.Exists(fileToCopy))
{
MessageBox.Show("file copied");
System.IO.File.Copy(fileToCopy, newLocation, true);
}
else
{
MessageBox.Show("no such files");
}
}
A fancy way is to extend the FileUpload with the method you want.
Add this:
public static class FileUploadExtension
{
public static void SaveAs(this FileUpload, string destination, bool autoCreateDirectory) {
if (autoCreateDirectory)
{
var destinationDirectory = new DirectoryInfo(Path.GetDirectoryName(destination));
if (!destinationDirectory.Exists)
destinationDirectory.Create();
}
file.SaveAs(destination);
}
}
Then use it:
FileUpload file;
...
file.SaveAs(path,true);
string root = #"C:\Temp";
string subdir = #"C:\Temp\Mahesh";
// If directory does not exist, create it.
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
The CreateDirectory is also used to create a sub directory. All you have to do is to specify the path of the directory in which this subdirectory will be created in. The following code snippet creates a Mahesh subdirectory in C:\Temp directory.
// Create sub directory
if (!Directory.Exists(subdir))
{
Directory.CreateDirectory(subdir);
}
Derived/combined from multiple answers, implementing it for me was as easy as this:
public void Init()
{
String platypusDir = #"C:\platypus";
CreateDirectoryIfDoesNotExist(platypusDir);
}
private void CreateDirectoryIfDoesNotExist(string dirName)
{
System.IO.Directory.CreateDirectory(dirName);
}

Categories

Resources