views:

1481

answers:

4

I've got a string like "Foo: Bar" that I want to use as a filename, but on Windows the ":" char isn't allowed in a filename.

Is there a method that will turn "Foo: Bar" into something like "Foo- Bar"?

A: 

Replace characters in your string, perhaps? Depends on what functions are available to you. You can map characters which are not allowed in filenames (such as ':') to those which are (such as '-'). Very simple task.

strager
+27  A: 

Try something like this:

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}

Edit: since GetInvalidFileNameChars() will return 10 or 15 chars, it's better to use a StringBuilder instead of a simple string; the original version will take longer and consume more memory.

Diego Jancic
Good call on S.I.P.GIFNC. The loop is roughly what I ended up doing, but I'm not crazy about calling string.Replace in a loop -- I was hoping there would be a builtin that was both simple *and* efficient.
Ken
You could use a StringBuilder if you wish, but if the names are short and i guess it's not worth it. You could also create your own method to create a char[] and replace all wrong chars in one iteration.Always is better to keep it simple unless it doesn't work, you might have worse bottle necks
Diego Jancic
I don't know c#, but is it not possible to use a remove() method that takes a set of characters? This set of characters appears to be handily provided by GetInvalidFileNameChars().Also, realistically, how many times will that loop iterate? 6 usually, 40 at most if the fnuction also returns non printed ascii, maybe?caveat: the msdn for that function also mentions that you should use GetInvalidPathChars, as GIFNC doesn't return a '\' or '/', which are invalid filename chars.
Pod
I don't know any "Remove" method, similar to the one you are talking about; even if it exist how it would be able to resolve faster? The only thing it could do is to copy the result of GIFNC to an array to avoid the call overhead (if any).Regarding the other comment, you should use GIFNC because this one is which returns the \ and /. Use Reflector to check the Path's static constructor if you wish. Here's the declarition in Windows (in Mono Linux might be different):
Diego Jancic
InvalidFileNameChars = new char[] { '"', '<', '>', '|', '\0', '\x0001', '\x0002', '\x0003', '\x0004', '\x0005', '\x0006', '\a', '\b', '\t', '\n', '\v', '\f', '\r', '\x000e', '\x000f', '\x0010', '\x0011', '\x0012', '\x0013', '\x0014', '\x0015', '\x0016', '\x0017', '\x0018', '\x0019', '\x001a', '\x001b', '\x001c', '\x001d', '\x001e', '\x001f', ':', '*', '?', '\\', '/' };
Diego Jancic
+13  A: 
fileName = fileName.Replace(":", "-")

However ":" is not the only illegal character for Windows. You will also have to handle:

/, \, :, *, ?, ", <, > and |

These are contained in System.IO.Path.GetInvalidFileNameChars();

Also (on Windows), "." cannot be the only character in the filename (both ".", "..", "...", and so on are invalid). Be careful when naming files with ".", for example:

echo "test" > .test.

Will generate a file named ".test"

Lastly, if you really want to do things correctly, there are some special file names you need to look out for. On Windows you can't create files named:

CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
Phil Price
I never knew about the reserved names. Makes sense though
Greg Dean
Also, for what it's worth, you can not create a filename starting with one of these reserved names, followed by a decimal. i.e. con.air.avi
John Conrad
".foo" is a valid filename. Didn't know about the "CON" filename - what is it for?
configurator
Scratch that. CON is for console.
configurator
Thanks configurator; I've updated the answer, you are correct ".foo" is valid; however ".foo." leads to possible, unwanted results. Updated.
Phil Price
OK now I'm scared.
Ken
+1  A: 

Diego does have the correct solution but there is one very small mistake in there. The version of string.Replace being used should be string.Replace(char, char), there isn't a string.Replace(char, string)

I can't edit the answer or I would have just made the minor change.

So it should be:

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}
leggetter
Good point. I've applied this update to Diego's answer.
Daniel Fortunov