File paths with non-ascii characters and FileInfo in C# - c#

I get a string that more or less looks like this:
"C:\\bláh\\bleh"
I make a FileInfo with it, but when I check for its existence it returns false:
var file = new FileInfo(path);
file.Exists;
If I manually rename the path to
"C:\\blah\\bleh"
at debug time and ensure that blah exists with a bleh inside it, then file.Exists starts returning true. So I believe the problem is the non-ascii character.
The actual string is built by my program. One part comes from the AppDomain of the application, which is the part that contains the "á", the other part comes, in a way, from the user. Both parts are put together by Path.Combine. I confirmed the validity of the resulting string in two ways: copying it from the error my program generates, which includes the path, into explorer opens the file just fine. Looking at that string at the debugger, it looks correctly escaped, in that \ are written as \. The "á" is printed literarily by the debugger.
How should I process a string so that even if it has non-ascii characters it turns out to be a valid path?

Here is a method that will handle diacritics in filenames. The success of the File.Exists method depends on how your system stores the filename.
public bool FileExists(string sPath)
{
//Checking for composed and decomposed is to handle diacritics in filenames.
var pathComposed = sPath.Normalize(NormalizationForm.FormC);
if (File.Exists(pathComposed))
return true;
//We really need to check both possibilities.
var pathDecomposed = sPath.Normalize(NormalizationForm.FormD);
if (File.Exists(pathDecomposed))
return true;
return false;
}

try this
string sourceFile = #"C:\bláh\bleh";
if (File.Exists(sourceFile))
{
Console.WriteLine("file exist.");
}
else
{
Console.WriteLine("file does not exist.");
}
Note : The Exists method should not be used for path validation, this method merely checks if the file specified in path exists. Passing an invalid path to Exists returns false.
For path validation you can use Directory.Exists.

I have just manuall created a bláh folder containing a bleh file, and with that in place, this code prints True as expected:
using System;
using System.IO;
namespace ConsoleApplication72
{
class Program
{
static void Main(string[] args)
{
string filename = "c:\\bláh\\bleh";
FileInfo fi = new FileInfo(filename);
Console.WriteLine(fi.Exists);
Console.ReadLine();
}
}
}
I would suggest checking the source of your string - in particular, although your 3k rep speaks against this being the problem, remember that expressing a backslash as \\ is an artifact of C# syntax, and you want to make sure your string actually contains only single \s.

Referring to #adatapost's reply, the list of invalid file name characters (gleaned from System.IO.Path.GetInvalidFileNameChars() in fact doesn't contain normal characters with diacritics.
It looks like the question you're really asking is, "How do I remove diacritics from a string (or in this case, file path)?".
Or maybe you aren't asking this question, and you genuinely want to find a file with name:
c:\blòh\bleh
(or something similar). In that case, you then need to try to open a file with the same name, and not c:\bloh\bleh.

Look like the "bleh" in the path is a directory, not a file. To check if the folder exist use Directory.Exists method.

The problem was: the program didn't have enough permissions to access that file. Fixing the permissions fixed the problem. It seems that when I didn't my experiment I somehow managed to reproduce the permission problem, possibly by creating the folder without the non-ascii character by hand and copying the other one.
Oh... so embarrassing.

Related

Constraint a path to be within a folder

Say you want to store a file within a folder C:\A\B\C and let the user supply the file name.
Just combine them, right?
Wrong.
If the user selects something like \..\..\Ha.txt you might be in for a surprise.
So how do we restrict the result to within C:\A\B\C? It's fine if it's within a subfolder, just not over it.
I've used one of my test projects, it really doesn't matter:
Using c#10
internal class Program
{
static void Main(string[] args)
{
string template = #"F:\Projectes\Test\SourceGenerators";
string folder = #"..\..\..\..\Test1.sln";
Console.WriteLine(MatchDirectoryStructure(template, folder)
? "Match"
: "Doesn't match");
}
static bool MatchDirectoryStructure(string template, string folder)
=> new DirectoryInfo(folder).FullName.StartsWith(template);
}
As you can see, new DirectoryInfo(fileName).FullName; returns the real name of the directory.
From here you can check if it match with the desired result.
In this case the returned value is:
Match
If you're asking for a file name, then it should be just the name of the file. The more control you give to the user about subdirectories, the more they can mess with you.
The idea here is to split your path by both possible slashes (/ and \) and see if the value of any of the entries in the array is ...
string input = #"\..\..\Ha.txt";
bool containsBadSegments = input
.Split(new [] { '/', '\\' })
.Any(s => s is "..");
This answer only takes care of detecting \..\ in the path. There are plenty of other ways to input bad values, such as characters not allowed by the OS's file system, or absolute or rooted paths.

Use Path.GetFileNameWithoutExtension method in C# to get the file name but the display is not complete

This is the simple C# code I wrote :
string file = #"D:\test(2021/02/10).docx";
var fileName = Path.GetFileNameWithoutExtension(file);
Console.WriteLine(fileName);
I thought I would get the string "test(2021/02/10)" , but I got this result "10)".
How can I solve such a problem?
I just wonder why would you want such behavior. On windows slashes are treated as separator between directory and subdirectory (or file).
So, basically you are not able to create such file name.
And since slashes are treated as described, it is very natural that method implementation just checks what's after last slash and extracts just filename.
If you are interested on how the method is implemented take a look at source code

Concatenation when creating a file name

I am trying to check if a file exists in a specific folder on the local machine. The file name is created by concatenation of the first and last names. I am not sure how to pass the file name into the file.exists since the file name changes each time? I am using the following statement to check the folder.
Code:
if(File.Exists(#"C:\TestDocuments\filename.xml"))
{
MessageBox.Show("The File Already Exists");
}
Path.Combine(String, String) concatenate the two strings, with an intervening separator character. I think here you need is string.format may be like
if(File.Exists(string.Format(#"C:\TestDocuments\{0}{1}.xml",firstName,lastName))
Kevin, as #Dai said you will want to use Path.Combine.
Your code afterwards might look something like this:
if(File.Exists(Path.Combine(directoryPath, filePath)))
{
MessageBox.Show("The File Already Exists");
}
This will combine a say "C:\TestDocuments" with "filename.xml" and can be used for other file names too.
You could essentially do something like this:
public static string CheckFileName(string name)
{
if(string.IsNullOrEmpty(name))
throw new ArgumentNullException();
int i = 0;
string file = Path.Combine(ConfigurationManager.AppSettings[#"FolderPath"], name);
while(File.Exist(file))
file = String.Format(file-{0}, i++);
return file;
}
That is an incredibly rough implementation, as it doesn't handle file extensions and or null values. But if the file exist it should auto increment until a file name that is free exist. This will alleviate files being overridden, but it all depends on your goal.
The above Does:
Pulls the path from your app.config, which would allow you to encrypt it.
Auto increments
Validates that the parameter isn't null.
Since it is a method, it is reusable.
The above Doesn't
Handle extensions in the file name.
Remove previous file, there isn't any overwriting.
When dealing with file paths, you often need Path.Combine to avoid any errors in slashes. That is where String.Format can run into issues, unless a separator exist. The Microsoft Developer Network has some great information on this.
You should check System.IO.

Validating File Path w/Spaces in C#

I'm something of a n00b at C# and I'm having trouble finding an answer to this, so if it's already been answered somewhere feel free to laugh at me (provided you also share the solution). :)
I'm reading an XML file into a GUI form, where certain elements are paths to files that are entered into TextBox objects. I'm looping through the controls on the form, and for each file path in each TextBox (lol there's like 20 of them on this form), I want to use File.Exists() to ensure it's a valid file.
The problem with this is that the file path can potentially contain spaces, and can potentially be valid; however File.Exists() is telling me it's invalid, based entirely on the spaces. Obviously I can't hard-code them and do something like
if (File.Exists(#"c:\Path To Stuff"))
and I tried surrounding the path with ", like
if (File.Exists("\"" + contentsOfTextBox + "\""))
but that didn't make a difference. Is there some way to do this? Can I escape the spaces somehow?
Thank you for your time. :)
File.Exists works just fine with spaces. There is something else giving you a problem I'll wager.
Make sure your XML reader isn't failing to read the filename (parts of XML do not allow spaces and some readers will throw an exception if they encounter one).
#"c:\Path To Stuff"
The above could be a directory not a file!
Hence you would want to use Directory.Exists!
#"c:\Path To Stuff\file.txt"
If you did have a file on the end of the path then you would use File.Exists!
As the answer said, File.Exists works with spaces, if you are checking for existence of a Directory however, you should be using Directory.Exists
What is the exact error that you get when File.Exists says it is invalid?
I suspect that you are passing a path to a directory and not a file, which will return false. If so, to check the presence of a directory, use Directory.Exists.
To echo Ron Warholic: make sure the process has permissions over the target folder. I just ran into the same "bug" and it turned out to be a permissions issue.
Did you remember to replace \ with \\ ?
You need to use youtStringValue.Trim() to remove spaces leading/trailing, and Replace to remove spaces in the string you do not want.
Also, rather use System.IO.Path.Combine rather to combine these strings.
You can use # on string variables:
string aPath = "c:\Path To Stuff\text.txt";
File.Exists(#aPath);
That should solve any escape character problems because I don't think this really looks like the spaces being the problem.
hi this is not difficult if you can convert the name of the path to a string array then go through one by one and remove the spaces
once that is done just write() to the screen where you have the files, if it is xml then your xmlmapper will suffice
file.exists() should only be used in certain circumstances if you know that it does exist but not when there can be space chars or any other possible user input

What's the best way to get the name of a folder that doesn't exist?

What's the best way to get a string containing a folder name that I can be certain does not exist? That is, if I call DirectoryInfo.Exists for the given path, it should return false.
EDIT: The reason behind it is I am writing a test for an error checker, the error checker tests whether the path exists, so I wondered aloud on the best way to get a path that doesn't exist.
Name it after a GUID - just take out the illegal characters.
There isn't really any way to do precisely what you way you want to do. If you think about it, you see that even after the call to DirectoryInfo.Exists has returned false, some other program could have gone ahead and created the directory - this is a race condition.
The normal method to handle this is to create a new temporary directory - if the creation succeeds, then you know it hadn't existed before you created it.
Well, without creating the directory, all you can be sure of is that it didn't exist a few microseconds ago. Here's one approach that might be close enough:
string path = Path.GetTempFileName();
File.Delete(path);
Directory.CreateDirectory(path);
Note that this creates the directory to block against thread races (i.e. another process/thread stealing the directory from under you).
What I ended up using:
using System.IO;
string path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
(Also, it doesn't seem like you need to strip out chars from a guid - they generate legal filenames)
Well, one good bet will be to concatenate strings like the user name, today's date, and time down to the millisecond.
I'm curious though: Why would you want to do this? What should it be for?
Is this to create a temporary folder or something? I often use Guid.NewGuid to get a string to use for the folder name that you want to be sure does not already exist.
I think you can be close enough:
string directoryName = Guid.NewGuid.ToSrtring();
Since Guid's are fairly random you should not get 2 dirs the same.
Using a freshly generated GUID within a namespace that is also somewhat unique (for example, the name of your application/product) should get you what you want. For example, the following code is extremely unlikely to fail:
string ParentPath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("TEMP"), "MyAppName");
string UniquePath = System.IO.Path.Combine(ParentPath, Guid.NewGuid().ToString());
System.IO.Directory.CreateDirectory(UniquePath);

Categories

Resources