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
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 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.
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
I had a question last week, and you quickly alleviated any concern that it would roadblock me, hoping that you can help a beginner program once more!
I'm trying to automate one of my daily mundane tasks and it's being quite a bugger, I think mainly because I'm not taking the correct approach.
Each morning I go through a system directory that houses many files with the same prefix, and a generated number following it. I have to sort alphabetically first, then remove the oldest versions of that file.
Here's an example pic of my directory: http://i.imgur.com/5l2Am.png
I was going to approach this situation by just sorting the files by name and comparing the first 3 letters to the following file, and if they were identical I would delete (or move to a backup folder) the second file, until they didn't match any longer, and I would move onto the next prefix as the comparator.
The problem with this though I found, is that they aren't always sorted correctly, and I risk deleting the wrong files.
Has anyone had experience with something of this nature? In my head and on VS I can put the pieces all there, but just can't seem to link it together, mainly because I've never ventured into the system.IO class before, but I want to learn!
Any advice is appreciated, and if you want to see my futile attempts I'll gladly share them :P.
Thanks,
Nick
You should be able to use Directory.GetFiles to retrieve the filenames. I suspect that your sorting problem is probably due to casing - in C#, string sorts, by default, as case sensitive, but the file system is not.
I'd recommend loading up the list of files, then sorting them yourself, in C#, prior to processing them:
List<string> files = Directory.GetFiles(myDirectory)
.Select(file => file.ToLower()) // To lower case
.OrderBy(file => file) // Sort the files
.ToList();
// Process the files here...
Create a dictionary indexed by the three character prefix.
When you reach a file, check the dictionary for a value:
if none exists, keep the file and add it to the dictionary, where the key is the prefix and the value is the number following the prefix
if one exists, but has an older "number" value, archive the old one, keep the newer one and update the dictionary to have the new number
if one exists, but has a newer "number" value, archive the old one, keep the newer one and the dictionary is already up to date at this point.
No sorting necessary.
EDIT: Adding example:
public static void ProcessDirectory(string directoryPath)
{
IDictionary<string,string> prefixDictionary = new Dictionary<string, string>();
if (Directory.Exists(directoryPath))
{
foreach(string filePath in Directory.GetFiles(directoryPath))
{
string fileName = Path.GetFileName(filePath);
string fileDirectory = Path.GetDirectoryName(filePath);
if (fileName.Length>=3)
{
string prefix = fileName.Substring(0, 3);
string rightPart = fileName.Substring(3, fileName.Length - 3);
if (!prefixDictionary.ContainsKey(prefix))
{
prefixDictionary[prefix] = rightPart;
}
else
{
string fileToArchive = null;
string storedRightPart = prefixDictionary[prefix];
// using string compare, but you could test file date or
// or parse the right part as a number if you only cared about
// files with numbers on the right.
if (String.Compare(storedRightPart,rightPart)<0)
{
prefixDictionary[prefix] = rightPart;
fileToArchive = Path.Combine(fileDirectory,prefix+storedRightPart);
}
else
{
fileToArchive = filePath;
}
if (fileToArchive != null)
{
// perform the archive here
}
}
}
}
}
}
You get get an array of FileInfo objects, which contain a lot of the metadata about the files, which would let you sort them. It also allows you to delete.
DirectoryInfo dir = new DirectoryInfo(#"C:/yourPath");
FileInfo[] files = dir.GetFiles();
From there, you can sort files by CreationTime or Name or whatever. To delete one, just use the Delete method on the FileInfo class.
When I add a picture I want it to create a new random file name because if you add a picture with the same name it will just overwrite.
The is a built-in method Path.GetRandomFileName. It returns a random folder name or file name.
The GetRandomFileName method returns a
cryptographically strong, random
string that can be used as either a
folder name or a file name. Unlike
GetTempFileName, GetRandomFileName
does not create a file. When the
security of your file system is
paramount, this method should be used
instead of GetTempFileName.
If you want to use your extension (e.g. .jpg instead of generated), you could use another helper method Path.ChangeExtension:
string extension = ".jpg";
string fileName = Path.ChangeExtension(
Path.GetRandomFileName(),
extension
);
System.IO.Path.GetRandomFileName gets a file name that is guaranteed to be unique.
As you want to save pictures, you could just use a GUID as the filename:
string filename = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".jpg");
I always do it this way when I need another file extension than .tmp (which files get when you create them via GetTempFileName).
Of course you could create the files via GetTempFileName and then rename them, but then you have to check again if a file with the new name exists...
You could generate a Guid and use that for your file name. Although this would mean that the files are not human readable and have no information as to what the content is.
Name your image using a GUID
For C# you can use: System.Guid.NewGuid().ToString()
You could built it using the current time.
string fileName = DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".png";
The above example will format the current time using year, month, day, hours, minutes, seconds, and fractions of a second. (The fraction of a second can be specified with fewer fs if you want it down to one.).
Advantages:
It will sort automatically by the created time in an alphabetically sorted list. (Like default sorting in Windows Explorer.)
It is human readable and provides useful information about the time it is created.
Disadvantages:
If this is a web application (or other sort of multi-thread process) there is a (small) chance of two files getting same name if generated at the same time. This is not an issue if this is a single-thread EXE.
Perhaps you are looking for GetTempFileName.
I would also go with the GUID solution.
Here some code I would use regularly:
public static string GetRandomFileName(string extension)
{
StringBuffer sb = new StringBuffer(Guid.NewGuid().ToString());
if (!string.IsNullOrEmpty(extensions))
{
sb.Append(".");
sb.Append(extension);
}
return sb.ToString();
}
Would provide you with a fine, reusable solution. Put this into your "collection of my greatest moments" - classlibrary and you are good to go.