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.
Related
This question already has answers here:
How to Generate unique file names in C#
(20 answers)
Closed 4 years ago.
I have this code here that take base 64 string and creates bytes, next I create a file name for these bytes.
byte[] bytes = System.Convert.FromBase64String(landingCells.imageBytes);
var filePath = landingCells.jobNo + DateTime.Now.ToString("yyyyMMddHHmmssffffff");
next I have save these bytes:
System.IO.File.WriteAllBytes("C:/app/Images/" + filePath + ".jpg", bytes);
The problem I am having is I am calling these lines of code in a loop via an iOS app and sometimes the yyyyMMddHHmmssffffff is the same as the previous item in the loop. My question, how can I make the file names more unique so this does not happen.
Try This by using Guid.NewGuid():
var uniquecode=Guid.NewGuid();
var filePath = landingCells.jobNo + DateTime.Now.ToString("yyyyMMddHHmmssffffff")+uniquecode;
Using a date-based name will limit your file creation rate to the frequency of the system clock (and is also not threadsafe) which is why you are seeing duplicate file names when you complete iterations of your loop too quickly. You have several options to make it more unique that depend on what your requirements are:
Add an incrementing counter suffix to the file name when the date is the same as the date of the last file written
Incorporate a GUID into the file name. This will be less readable than the counter suffix but will guarantee uniqueness even across a distributed system and won't require you to maintain a counter.
Incorporate some other original information about the file or its metadata into the name that when combined with the date will be unique
Come up with some custom name generation algorithm that will generate unique names for every (even repeated) input. How you do this depends on the domain you're working within and the data you're dealing with.
I'm not sure what kind app you're building, but it's worth reevaluating whether you actually need to write that many images to disk per second and if you do whether a video would be better. Throttling the writes would probably not be a bad idea and it would also solve the naming problem.
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.
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
I need to build a unique filename in a multithreaded application which is serializing some data on the disk.
What approach could I use to ensure a unique name.
The app was not multithreaded before and was using Ticks. When using multiple threads, it failed much faster than I expected.
I now added the CurrentThreadId to the filename, and that should do it
string.Format("file_{0}_{1}.xml", DateTime.Now.Ticks, Thread.CurrentThread.ManagedThreadId)
Is there any "smarter" way of doing this?
What about Guid.NewGuid() instead of the thread id?
string.Format("file_{0}_{1:N}.xml", DateTime.Now.Ticks, Guid.NewGuid())
By keeping the ticks as part of the name, the names will still be in approximate date order if ordering is important.
The {1:N} gets rid of the curly braces and dashes in the guid.
Also, consider using DateTime.UtcNow.Ticks, so as to guarantee incremental ticks when daylight saving time kicks in.
Depending on your needs you can try:
System.IO.Path.GetTempFileName();
This creates a uniquely named temporary file in the %temp% directory. I suppose you can copy the file to your target location before or after writing to it.
To actually reserve the filename you will have to create the file immediately and check for exceptions.
Another option would be to include a Guid value in your filename.
How about
Guid.NewGuid().ToString()