Consider the following code snippet
public static string AppendDateTimeToFileName(this string fileName)
{
return string.Concat(
Path.GetFileNameWithoutExtension(fileName),
DateTime.Now.ToString("yyyyMMddHHmmssfff"),
Path.GetExtension(fileName));
}
This basically puts a date time stamp on any file that is being uploaded by the users. Now this works great is the file name is something like
MyFile.png
AnotherFile.png
Now I'm trying to change this method so if the file name is something like
MyFile - Copy(1).png
AnotherFile - Copy(1).png
I want the file name to become
MyFile-Copy-120170303131815555.png
AnotherFile-Copy-120170303131815555.png
If there an easy soltuion for this with regex or similar or do I have to re-write the method again and check each of those values one by one.
return string.Concat(
Regex.Replace(Path.GetFileNameWithoutExtension(fileName), #" - Copy\s*\(\d+\)", "-Copy-", RegexOptions.IgnoreCase),
DateTime.Now.ToString("yyyyMMddHHmmssfff"),
Path.GetExtension(fileName));
This matches any number of digits and is a global replace.
Related
One of our tool here maintains file in format like - file.txt.1.
Last 1 is numeric value always and is increased on each file save , so that file system has multiple files.
Now in another C# application I would like to process these file name. In this I want to split basename and extension.
I used Path.GetFilenameWithoutExtension() and Path.GetExtension(). In this case they will return file.txt and .1 respectively.
This forced me to run another round of call to get file name without extension and file extension.
Is there any simple/smart way to have basename and extension?
I don't think that there is a much SIMPLER way than your first idea.
Nevertheless, using a regular expression for this has the advantage that you have better control over filtering out the file with the correct syntax. I just wrote a small sample:
...
using System.IO;
using System.Text.RegularExpressions;
...
string path = #"C:\temp";
Regex numExtRegex = new Regex(#"^(.*)\.(\d+)$");
foreach (string file in Directory.GetFiles(path))
{
Match match = numExtRegex.Match(file);
if (match.Success)
{
string originalFile = match.Groups[1].Value;
string numericExtension = match.Groups[2].Value;
string originalFileNameWithoutExtension = Path.GetFileNameWithoutExtension(originalFile);
string extension = Path.GetExtension(originalFile);
Console.WriteLine("File: {0}, numeric extension: {1}, file name w/o ext: {2}, ext: {3}",
originalFile, numericExtension, originalFileNameWithoutExtension, extension);
}
}
The regular expression looks for something.digits
Using this way of filtering, you can be sure that you don't handle e.g. a readme.txt which someone placed into the directory...
I've got a string that, among other things, contains a full file path. I'd like the strip out the directory portion of the file path and return the rest of the string. Here's an example:
"This - string - is 1 string of text with /this/full/file.path in it."
Which I'd like to reduce to:
"This - string - is 1 string of text with file.path in it."
Any ideas how to make this one work?
Using ([^/]*$) is nice but strips off all the characters before the file path. I'm having a hard time figuring out how to break it into the part before the first / and the part after with doing the substition on the second piece.
Thanks!
\/.*\/
Try this.Replace by empty string.See demo.
https://regex101.com/r/vN3sH3/9
or
[^\s]*\/.*\/
If you have string like This - string - is 1 string of text with dsfsdf/this/full/file.path in it.See demo.
https://regex101.com/r/vN3sH3/11
Another option could be to use Path.GetFileName
(MSDN Example)
string fileName = #"C:\mydir\myfile.ext";
string path = #"C:\mydir\";
string result;
result = Path.GetFileName(fileName);
Console.WriteLine("GetFileName('{0}') returns '{1}'",
fileName, result);
result = Path.GetFileName(path);
Console.WriteLine("GetFileName('{0}') returns '{1}'",
path, result);
// This code produces output similar to the following:
//
// GetFileName('C:\mydir\myfile.ext') returns 'myfile.ext'
// GetFileName('C:\mydir\') returns ''
Don't use a Regex.
use System.IO.Path.GetFileName("/this/full/file.path");
I need a function that gives a one-to-one map from a string to another string, but the output string the nice property of being a proper name for a file.
More specifically my problem is that, given a URL of an image, I want to save the image with a unique name given that URL. I need a code like this
string url;
string uniqueName = UrlToName (url);
string fileName = path + uniqueName + ".png";
The problem is how to get the UrlToName function. An possible solution could be GetHashCode but I don't know if its correct.
Your best bet is to use a database - create a new row for each file, store the Uri in one column and a generated file name in another column (e.g. Guid.NewGuid().ToString() + ".png").
This is immune to any problems with file name lengths (~255 characters in NTFS whilst a URL could be ~2000), there is no chance of a hash collision and you can evolve your storage algorithm over time as your database grows, for example, adding directories so that you don't end up with too many files in a single directory (which makes it unuseable in Explorer).
You should also be concerned about security risks if you ever create file names on a server based on external input. Much of the advice in this answer applies here too.
Try something like this:
private string UrlToName(string url)
{
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
url = url.Replace(c, '_');
}
return url;
}
This will make sure that it has valid file name characters. As long as the url being passed in is unique, then this function should always return a unique string back.
If you do need a truly unique name, even if the same URL gets passed in, try this:
private string UrlToName(string url)
{
url = url + "_" + DateTime.Now.ToString("o");
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
url = url.Replace(c, '_');
}
return url;
}
This will add a date stamp, down to the milliseconds to the end of the string. Unless you pass in the exact same URL, at the same exact millisecond (highly unlikely), you will get a unique string back everytime.
I have a reasonably straight-forward question here but I seem to find myself revisiting each time I have to deal with the validation of file paths and names. So I'm wondering if there is a method available in System.IO or some other library in the framework that can make my life easier!?
Lets take the contrived example of a method that takes a file path and a filename and from these inputs it formats and returns unique full file-location.
public string MakeFileNameUnique(string filePath, string fileName)
{
return filePath + Guid.NewGuid() + fileName;
}
I know that I must do the following to get the path in a correct format so that I can append the guid and filename:
if filePath is null or empty then throw exception
if filePath does not exist then throw exception
if no valid postfixed '/' then add one
if it contains a postfixed '\' then remove and replace with a '/'
Can someone tell me if there is a framework method that can do this(particularly the forwareslash/backslash logic) available to achieve this repetitive logic?
Are you looking for the Path.Combine method:
public string MakeFileNameUnique(string filePath, string fileName)
{
return Path.Combine(filePath, Guid.NewGuid().ToString(), fileName);
}
but looking at the name of your method (MakeFileNameUnique), have you considered using the Path.GenerateRandomFileName method? Or the Path.GetTempFileName method?
Following your requirements this will do
public string MakeFileNameUnique(string filePath, string fileName)
{
// This checks for nulls, empty or not-existing folders
if(!Directory.Exists(filePath))
throw new DirectoryNotFoundException();
// This joins together the filePath (with or without backslash)
// with the Guid and the file name passed (in the same folder)
// and replace the every backslash with forward slashes
return Path.Combine(filePath, Guid.NewGuid() + "_" + fileName).Replace("\\", "/");
}
a call with
string result = MakeFileNameUnique(#"d:\temp", "myFile.txt");
Console.WriteLine(result);
will result in
d:/temp/9cdb8819-bdbc-4bf7-8116-aa901f45c563_myFile.txt
However I wish to know the reason about the replace for the backslash with forward slashes
I'd like to trim these purchase order file names (a few examples below) so that everything after the first "_" is omitted.
INCOLOR_fc06_NEW.pdf
Keep: INCOLOR (write this to db as the VendorID) Remove: _fc08_NEW.pdf
NORTHSTAR_sc09.xls
Keep: NORTHSTAR (write this to db as the VendorID) Remove: _sc09.xls
Our scenario: The managers are uploading these files to our Intranet web server, to make them available to download/view ect. I'm using Brettles NeatUpload, and for each file uploaded, am writing the files attributes into the PO table (sql 2000). The first part of the file name will be written to the DB as a VendorID.
The naming convention for these files is consistent in that the the first part of the file is always the vendor name (or Vendor ID) followed by an "_" then other unpredictable chars used to identify the type of Purchase Order then the file extention - which is consistently either .xls, .XLS, .PDF, or .pdf.
I tried TrimEnd - but the array of chars that you have to provide ends up being long and can conflict with the part of the file name I want to keep. I have a feeling I'm not using TrimEnd properly.
What is the best way to use string.TrimEnd (or any other string manipulation in C#) that will strip off all chars after the first "_" ?
String s = "INCOLOR_fc06_NEW.pdf";
int index = s.IndexOf("_");
return index >= 0 ? s.Substring(0,index) : s;
I'll probably offend the anti-regex lobby, but here I go (ducking):
string stripped = Regex.Replace(filename, #"(?<=[^_]*)_.*",String.Empty);
This code will strip all extra characters after the first '_', unless there is no '_' in the string (then it will just return the original string).
It's one line of code. It's slower than the more elaborate IndexOf() algorithm, but when used in a non-performance-sensitive part of the code, it's a good solution.
Get your flame-throwers out...
TrimEnd removes white spaces and punctuation marks at the end of the String, it won't help you here. Read more about TrimEnd here:
http://msdn.microsoft.com/en-us/library/system.string.trimend.aspx
Bnaffas code (with a small tweak):
String fileName = "INCOLOR_fc06_NEW.pdf";
int index = fileName.IndexOf("_");
return index >= 0 ? fileName.Substring(0, index) : fileName;
If you want to do something with the other parts, you could use a Split
string fileName = "INCOLOR_fc06_NEW.pdf";
string[] parts = fileName.Split('_');
public string StripOffStuff(string sInput)
{
int iIndex = sInput.IndexOf("_");
return (iIndex > 0) ? sInput.Substring(0, iIndex) : sInput;
}
// Call it like:
string sNewString = StripOffStuff("INCOLOR_fc06_NEW.pdf");
I would go with the SubString approach but to round out the available solutions here's a LINQ approach just for fun:
string filename = "INCOLOR_fc06_NEW.pdf";
string result = new string(filename.TakeWhile(c => c != '_').ToArray());
It'll return the original string if no underscore is found.
To go with all the "alternative" solutions, here's the second one that I thought of (after substring):
string filename = "INCOLOR_fc06_NEW.pdf";
string stripped = filename.Split('_')[0];