C# read/write in case sensitive path - c#

I have a problem.
I save json from web, in json files on my computer, and the name of this json file, is the web adress of the json.
For that, I get the web json into string, and then I append it in a file, with File.AppendAllText(path, content)
After some time, i also need to read json from this file with File.ReadAllText(path)
My problem is sometimes, two json have a very similar name, for example :
*com/doc/BACr and
*com/doc/BAcr
Problem, the path given in the methods of the class File are note case sensitive, and I end writing twice in the same file, corrupting it.
I've found on the internet solutions for the same problem for the method File.Exists(path), but nothing to replace the methods I use to read or write.
Any of you know a setting, or even another method that would be case sensitive on the path ?
Thank you
Edit : I'm obviously working on windows :(
Edit bis : I can't change the filename, because in some others json, there is reference to web path, and when I play again my local jsons, if the filename is modified, it won't be found. It's the reason I need both write and read with case sensitive path.

You need something that makes your files unique and in the same time something that allows you to rebuild this uniqueness when you want to read back these files.
Suppose that your couple of files is named "BAcr" and "BACr". You can get the HashCode of these two strings and you will get two different values
string file1 = "BAcr";
int file1Hash = file1.GetHashCode(); //742971449
string file2 = "BACr";
int file1Hash = file2.GetHashCode(); //-681949991
Now if you concatenate this hashcode to your filename you will get two different files and you will be able to recalculate the same hashcode for the same input filename
string newFile1 = $"{file1}.{file1Hash}";
string newFile2 = $"{file2}.{file2Hash}";
you will save your data in these two recalculated filenames and when you need to reload them you use the same trick to get the filename used to save the data starting from the same input "BAcr" or "BACr".
But string.GetHashCode doesn't guarantee uniqueness in its results so, still using the same general idea Jeroen Mostert uses this method to get an unique code from the input value
string unique1 = string.Join("", file1.Select(c => char.IsUpper(c) ? "1" : "0"))
string newFileName1 = $"{file1}.{unique1}";

Windows paths are indeed case insensitive, so you cannot have these filenames.
One solution would be to change the filename if it already exists...
For example;
if (File.Exists(fileNameToSaveTo)){
// Note: Your example file names did not have an extension,
// but if they do, you will need to first extract that then add it back on
fileNameToSaveTo = fileNameToSaveTo + "1";
}
If using this solution, you would have to also update whatever identifier your program uses to read back from the file at a later date... as you have not posted any code I cannot guess as to what form this takes, but hopefully you get the idea?
Edit:
Upon re-reading your question... it appears you use AppendAllText... In this case, this should not 'corrupt' the file as you suggest, but should simply add the contents to the end of the file? Is this not what you observe?
Edit2:
After reading comments Iomed - you could use Convert.ToBase64String on the filename in your write before writing the file, the use Convert.FromBase64String on the filename in your read function before reading the file. This will allow the filename to be different based on the capitalization.
Another alternative would be to parse the JSON (the new one AND the existing file) and add the objects to an array, then write that to the file instead, avoiding your 'corruption' issue?

given paths: PathA, patha
for two files, use base64 trick:
string PathToFile(string url) => System.Convert.ToBase64String(Encoding.UTF8.GetBytes(url));
so:
Console.WriteLine(PathToFile("pathA")); //cGF0aEE=
Console.WriteLine(PathToFile("patha")); //cGF0aGE=

Related

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.

c# Search text files for specific string and get file path

Using c# in a Windows Form I need to search a directory "C:\XML\Outbound" for the file that contains an order number 3860457 and return the path to the file that contains the order number so I can then open the file and display the contents to the user in a RickTextBox.
The end user will have the order number but will not know what file contains that order number so that is why I need to search all files till it finds the filecontaining the order number and return the path (e.g. "C:\XML\Outbound\some_file_name_123.txt")
I am somewhat new to c# so I am not even sure where to start with this. Any direction for this?
Sorry the order number is inside the file so I need to search each file contents for the order number and once the file containing the order number is found return the path to that file. Order number is not part of the file name.
Straight answer:
public string GetFileName(string search){
List<string> paths = Directory.GetFiles(#"C:\XML\Outbond","*.txt",SearchOption.AllDirectories).ToList();
string path = paths.FirstOrDefault(p=>File.ReadAllLines(p).Any(line=>line.IndexOf(search)>=0));
return path;
}
Not-so straight answer:
Even though the above function will give you the path for given string (some handling of errors and edge cases may be nice) it will be terribly slow, especially if you have lots of files. If that's the case you need to tell us more about your environment because chances are you're doing it wrong (:

Downloading/Uploading file, what characters to filter c#

In my application I build a static string when a user uploads or downloads a file. In that string the filename is passed from the frontend in that string. In this way the user could do things like ..\..\another file.file to tamper and get data from other users. Therefor I need to filter the filename that I get to prevent this. What are the characters that need to be filtered to prevent tampering? I now have the double dot and the back and forward slashes. Is there anything else I should take into consideration? Is there maybe a standard way to do this in C#?
I would suggest using Path.GetInvalidFileNameChars:
public static bool IsValidFileName(string fileName)
{
return fileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
}
.. is typically only dangerous when preceded and/or succeeded by a \ or /, both of which are included in the array returned by GetInvalidFileNameChars. By itself, .. is harmless (unless you’re specifically resolving directory paths), and you shouldn’t forbid it since people might want to introduce ellipses in their filename (e.g. The A...Z of Programming.pdf).
What if different users save a file with the same name? Are you creating a folder for each user?
Most likely what you should be doing is storing the name they provide in a database record, which also contains a pointer to the actual file (which uses a file name which you generate, perhaps a guid). You could also consider using the filestream data type if you'd like to save the document in the database as well.
Nothing good can come from letting your users determine file names on your server :)

How to handle paths to files with extra parameters in C#?

I'm downloading files from the Internet inside of my application. Now I'm dealing with multiple file types so I need to able to detect what file type the file is before my application can continue. The problem that I ran into is that some of the URLs where the files are getting downloaded from contain extra parameters.
For example:
http://www.myfaketestsite.com/myaudio.mp3?id=20
Originally I was using String.EndsWith(). Obviously this doesn't work anymore. Any idea on how to detect the file type?
Wrap the URL in a Uri class. It will split it up into different segments that you can use, or you can use the helper methods on the Uri class itself:
var uri = new Uri("http://www.myfaketestsite.com/myaudio.mp3?id=20");
string path = uri.GetLeftPart(UriPartial.Path);
// path = "http://www.myfaketestsite.com/myaudio.mp3"
Your question is a duplicate of:
Truncating Query String & Returning Clean URL C# ASP.net
Get url without querystring
You could always split on the question mark to eliminate the parameters. e.g.
string s = "http://www.myfaketestsite.com/myaudio.mp3?id=20";
string withoutQueryString = s.Split('?')[0];
If no question mark exists, it won't matter, as you'll still be grabbing the value from the zero index. You can then do your logic on the withoutQueryString string.

Categories

Resources