String appears differently depending on use scenario - c#

Getting some odd behavior with JSON data which is being loaded into an observablecollection.
Here's an example of the JSON import, and how my folder path is shown.
{
"projectNumber":"16000",
"projectName":"Sample Project",
"Directory":"#\"C:\\Users\"", }
So far I've been able to use the data as expected after loading into my observablecollection. For example, the messagebox shows (selectedfolder) in the messagebox as intended: #"C:\Users"
This is the path I want my treeview to use. Oddly, it's not using that but instead uses the original path format from my JSON import instead ("#\"C:\Users\"") and throws an "Illegal characters in path" error.
private void ListDirectory(TreeView treeView, string path)
{
treeView.Items.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Items.Add(CreateDirectoryNode(rootDirectoryInfo));
}
private static TreeViewItem CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeViewItem { Header = directoryInfo.Name };
foreach (var directory in directoryInfo.GetDirectories())
directoryNode.Items.Add(CreateDirectoryNode(directory));
foreach (var file in directoryInfo.GetFiles())
directoryNode.Items.Add(new TreeViewItem { Header = file.Name });
return directoryNode;
}
private void button_Click(object sender, RoutedEventArgs e)
{
Project selectedProject = comboBox.SelectedItem as Project;
selectedfolder = selectedProject.Directory.ToString();
MessageBox.Show(selectedfolder);
if (selectedProject != null)
{
this.ListDirectory(treeView, selectedfolder);
}
Anybody see what I'm missing here, and why the same string would appear differently depending on how it's being used?

The #"" string literal is used to help write code that has strings with backslashes in it. This bit of code, for instance, contains a reference to a valid path, and the #"" bit just tells the C# compiler to treat backslashes differently than normal C-style strings:
string example1 = #"C:\Users";
Debug.WriteLine(example1); // Outputs C:\Users
// This works
var temp1 = new DirectoryInfo(example1);
Once you actually embed the #"" bit in a string, you end up with a string that contains # and " characters in it, which isn't going to be a valid path on Windows.
string example2 = "#\"C:\\Users\"";
Debug.WriteLine(example2); // Outputs #"C:\Users"
// This throws an exception
var temp2 = new DirectoryInfo(example2);
In other words: Using #"" is fine for C# code, but for a JSON object, you'll need to change your JSON text to be something like this, using \ to escape characters, so it's a valid path after the JSON deserializer finishes parsing the string:
{
"projectNumber":"16000",
"projectName":"Sample Project",
"Directory":"C:\\Users",
}

That was clearly the answer. Thanks so much, Anon! What was throwing me off was how the string showed in a messagebox exactly how I would use it in a path reference. Newbie mistake!

Related

File.Exists(Path) always return false when get 'string (Path)' from text file

I write codes to receive the path of a text file and store it in a string variable that I declare in public.
Then I want to know if the file exists or not by using
System.IO.File.Exists(pathoffile)
But it always returns false even though there is a file.
And then when I try to add the string path directly like this
public string propertyfile = #"C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt"
The function
System.IO.File.Exists(pathoffile)
return true
I already check the receive path(string) that I read from the text file. By cutting off "\n" and "\r" and using trim() too.But it still returns false.
Have I missed something? What difference between these two?. I'm too new to this c#. I'm very bad at this sorry in advance.
Here are my codes
public string pathfromread, partnumber, pathfile, portname, partnofromserial,propertypathfile; //Declare Variables
public string propertyfile = #"C:\Users\PFA Wongsawat\Desktop\Properties.txt";
public string pathoffile ;
public string backuppath ;
public string pdffolderpath ;
private void propertyget()
{
if (File.Exists(propertyfile))
{
StreamReader readpropertyfile = new StreamReader(propertyfile);
string readproperty;
while ((readproperty = readpropertyfile.ReadLine()) != null)
{
string[] propertyfromread = readproperty.Trim().Split('=');
if (propertyfromread.GetValue(0).ToString() == "pathoffile")
{
pathoffile = propertyfromread.GetValue(1).ToString();
pathoffile = pathoffile.Replace("\n", "").Replace("\r", "");
MessageBox.Show(pathoffile, "path file");
}
else if ((propertyfromread.GetValue(0).ToString() == "backuppath"))
{
backuppath = propertyfromread.GetValue(1).ToString();
backuppath = backuppath.Replace("\n", "").Replace("\r", "");
MessageBox.Show(backuppath);
}
else if ((propertyfromread.GetValue(0).ToString() == "pdffolderpath"))
{
pdffolderpath = propertyfromread.GetValue(1).ToString();
pdffolderpath = pdffolderpath.Replace("\n", "").Replace("\r", "");
MessageBox.Show(pdffolderpath);
}
else if ((propertyfromread.GetValue(0).ToString() == "portname"))
{
portname = propertyfromread.GetValue(1).ToString();
portname = portname.Replace("\n", "").Replace("\r", "");
MessageBox.Show(portname);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
propertyget();
dv = dt.DefaultView; //set dv index count to != 0 to prevent error from null input when click on remove button
if (System.IO.File.Exists(pathoffile))//Check if file exist or not
{
}
else
{
try
{
MessageBox.Show("Database Text File Missing. Please Select New File", "Database Text File Missing", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
OpenFileDialog regispath = new OpenFileDialog();
regispath.Title = "Select Database Text File (part_no_and_path_list.txt)";
regispath.Multiselect = false;
regispath.Filter = "Text file (*.txt)|*.txt";
regispath.RestoreDirectory = true;
regispath.ShowDialog();
pathfile = regispath.FileName;
File.Copy(pathfile, pathoffile);
}
catch
{
And this is my property text file
pathoffile=#"C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt"
backuppath=#"C:\Users\PFA Wongsawat\Documents\part_no_and_path_list.txt"
pdffolderpath=#"C:\Users\PFA Wongsawat\Downloads\"
portname=COM3
In this case the result always a messageBox showing "Database Text File Missing. Please Select New File"
Thank you and sorry for my bad English.
You don't put #" and " in the text file, you only put them in the code because that's how the c# compiler knows they're strings (and knows not to interpret slashes as an escape character)
Just make your text file look like:
pathoffile=C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt
I also recommend you use:
Split(new []{'='}, 2)
This will allow you to use = in your path, by making split return a maximum of 2 split values; any = that are legitimately in the path would be preserved
Actually I recommend you use one of the various built in settings mechanisms that c# has; we haven't needed to read and write our own configuration files for about 25 years
If you really do want to continue rolling your own you can reduce your code massively by using a dictionary
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class Settings{
private Dictionary<string,string> _conf = new Dictionary<string,string>();
public string PathOfFile {
get => _conf["pathoffile"];
}
public void ReadConfig(){
File.ReadAllLines("conf.txt").ToDictionary(
x => x.Split(new[]{'='},2)[0],
x => x.Split(new[]{'='},2)[1]
);
}
}
Yep, it's all you need. Every time you want to add another setting, add another property (like public string PathOfFile), add another love to the file and make sure the string in the property matches the line in the file
In other areas, please read up on c# naming conventions; PublicThingsAreNamedLikeThis, _privateLikeThis, localLikeThis, neverlikethis
Thank you I've already solved this problem
By remove "#" and '""' from path in the property text file like this.
pathoffile=C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt
backuppath=C:\Users\PFA Wongsawat\Documents\part_no_and_path_list.txt
pdffolderpath=C:\Users\PFA Wongsawat\Downloads\
portname=COM3
The reason I can't see this because I debug the program by seeing the result in message box and it not match with the real one. Thank you.

Removing ../ in the middle of a relative path

I want to get from this
"../lib/../data/myFile.xml"
to this
"../data/myFile.xml"
I guess I could do it by manipulating the string, searching for "../" and canceling them out with the preceding folders but I was looking for an already existing C# solution.
Tried instantiating an Uri from this string and going back toString(). Didn't help. It leaves the string unchanged.
You can always try to use:
Path.GetFullPath("../lib/../data/myFile.xml")
It behaves as you want with absolute paths but you might end up with strange behaviors with relative paths since it always bases itself from the current working directory. For instance:
Path.GetFullPath("/lib/../data/myFile.xml") // C:\data\myFile.xml
Path.GetFullPath("../lib/../data/myFile.xml") // C:\Program Files (x86)\data\myFile.xml
Sounds like you may either need to parse/rebuild the path yourself, or use some kind of well constructed regular expression to do this for you.
Taking the parse/rebuild route, you could do something like:
public static string NormalisePath(string path)
{
var components = path.Split(new Char[] {'/'});
var retval = new Stack<string>();
foreach (var bit in components)
{
if (bit == "..")
{
if (retval.Any())
{
var popped = retval.Pop();
if (popped == "..")
{
retval.Push(popped);
retval.Push(bit);
}
}
else
{
retval.Push(bit);
}
}
else
{
retval.Push(bit);
}
}
var final = retval.ToList();
final.Reverse();
return string.Join("/", final.ToArray());
}
(and yes, you'd probably want better variable names/commenting/etc.)
You can use a regular expression to do this:
public static string NormalisePath(string path)
{
return new Regex(#"\.{2}/.*/(?=\.\.)").Replace(path, "");
}

String returning with a null reference value

I have a silly error I can't get shot of.
I'm using a string to check the name of folders and their extension types. I'm doing this so I can navigate between folders. This works fine with my first folder selection, however, when I try and click on a second one I get null reference exception.
This is what I have at the moment.
string clickObject = listBox1.SelectedItem.ToString();
int index = clickObject .LastIndexOf('.');
string extension = clickObject .Substring(index + 1, clickObject .Length - index - 1);
if (extension == "folder")
{
// do stuff
}
After this I simply check the files in my folder.
When I go back to the root of my searchable folder and click on another directory, that is when i get the error and the line string clickObject = listBox1.SelectedItem.ToString(); is highlighted.
At the end of my method where I set this I tried setting clickedObject = null; I tried to remove the string that was contained with clickObject.Remove(0); but the error still persists.
How can I clear the information held in clickedObject so I can overwrite it with new information?
Edit
Sorry forgot to mention when I go back to the root I have a button that calls this method:
using (var client = new WebClient())
{
result = client.DownloadString("http://foo.foo.com/images/getDirectoryList.php");
}
string[] names = result.Split('|');
listBox1.Items.Clear();
foreach (string name in names)
{
listBox1.Items.Add(name);
}
listBox1.Update();
listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
However, when I click an item in the list box, its the first set of code that gets used and that is in a sepearate method.
If you are handling the SelectedIndexChanged event you need to cope with it being null as there are cases where it won't be set.
Therefore in your handler you must check that listBox1.SelectedItem is not null before trying to convert it to a string:
if (listBox1.SelectedItem != null)
{
// Your code
}
Not sure if this is a bug.. but I too have come across this before.
The problem is, that SelectedItem isn't always available during the SelectedIndexChanged event.. or sometimes not at all.
The fix is to access the item directly:
string clickObject = listBox1.Items[listBox1.SelectedIndex].ToString();
Also, while you're there.. you can use File.GetExtension method in System.IO to get the extension (instead of doing it yourself):
using System.IO;
string extension = File.GetExtension(clickObject);

Open file on combobox selection

I have a combobox which gets the list of items from the name of files I put together in one directory, the purpose for this is to make it dynamic - I'm very new to c# and it didn't occur to me a different way. - Here's the code for that bit:
string[] files = Directory.GetFiles(templatePath);
foreach (string file in files)
cbTemplates.Items.Add(System.IO.Path.GetFileNameWithoutExtension(file));
Basically, that works just fine, it populates my combobox with the names of the files I have in that path, the problem is that I need to open the file that's selected in the combobox and read its contents and place them in labels, I was thinking maybe StreamReader would help me here but I have NO clue on how to implement it, I've searched the internet but it looks like no one had the same idea before me. Can someone please point me in the right direction? A link to something similar or a guide of the objects I need to use would be great, thanks!
what you should do is store the names of the files in a single separate file (csv or xml). then use this file to both load the combobox and as an indexer.
for example lets say you have files a.txt, b.txt, and c.txt. you should (as you already are) read the file names programmatically THEN write them to a new file in whichever format you want, including a unique index scheme (numbers work fine).
your csv might look like this:
1, a.txt,
2, b.txt,
3, c.txt,
from here you can parse the newly created csv to your liking. Use it to populate your combobox, index being its value and filename its text. Then you can read your combobox selectedvalue, get the proper filename from the csv index, and finally open the file.
It may be longwinded but it'll work. You could also just use a multidimensional array, but this is more fun from an educational stand point, and it will help you with read/write operations.
It is not so easy to understand your problem. Do you want just to display filename w/o extension in your combobox? I hope this code will be usefull to you.
internal class FileDetail
{
public string Display { get; set; }
public string FullName { get; set; }
}
public partial class Example: Form // This is just widows form. InitializeComponent is implemented in separate file.
{
public Example()
{
InitializeComponent();
filesList.SelectionChangeCommitted += filesListSelectionChanged;
filesList.Click += filesListClick;
filesList.DisplayMember = "Display";
}
private void filesListClick(object sender, EventArgs e)
{
var dir = new DirectoryInfo(_baseDirectory);
filesList.Items.AddRange(
(from fi in dir.GetFiles()
select new FileDetail
{
Display = Path.GetFileNameWithoutExtension(fi.Name),
FullName = fi.FullName
}).ToArray()
);
}
private void filesListSelectionChanged(object sender, EventArgs e)
{
var text = File.ReadAllText(
(filesList.SelectedItem as FileDetail).FullName
);
fileContent.Text = text;
}
private static readonly string _baseDirectory = #"C:/Windows/System32/";
}
Thanks for all your help folks but I figured out how to get around my issue, I'll post the code for future incidents. pd. Sorry it took me this long to reply, I was on vacation
string[] fname = Directory.GetFiles(templatePath); // Gets all the file names from the path assigned to templatePath and assigns it to the string array fname
// Begin sorting through the file names assigned to the string array fname
foreach (string file in fname)
{
// Remove the extension from the file names and compare the list with the dropdown selected item
if (System.IO.Path.GetFileNameWithoutExtension(file) != cbTemplates.SelectedItem.ToString())
{
// StreamReader gets the contents from the found file and assigns them to the labels
using (var obj = new StreamReader(File.OpenRead(file)))
{
lbl1.Content = obj.ReadLine();
lbl2.Content = obj.ReadLine();
lbl3.Content = obj.ReadLine();
lbl4.Content = obj.ReadLine();
lbl5.Content = obj.ReadLine();
lbl6.Content = obj.ReadLine();
lbl7.Content = obj.ReadLine();
lbl8.Content = obj.ReadLine();
lbl9.Content = obj.ReadLine();
lbl10.Content = obj.ReadLine();
obj.Dispose();
}
}
}

C# String Property and string literal concatenation issue

I am a bit new at C# and I have run into a string concatenation issue. I am hoping someone might be able to give me a hint and help me resolve this. I have searched Google extensively and have spent more than a week on this so any help/advice would be greatly appreciated.
I have created a custom PathEditor for a string property. The property basically allows the user to key in a file to use in the app. If the file typed in is correct, it shows in the property cell as it should. What I am trying to do is output to the property cell an error message if the file typed in does not exist - I check this in my file validator. Here is the string literal issue.
If I use:
return inputFile+"Error_";
this works OK and I get the outpur file123.txtError_ in the property grid cell.
If I use:
return "Error_"+inputFile;
I get only the inputFile without the literal "Error_". Sot he property grid cell shows file123.txt in the property grid cell.
I have checked and inputFile is a string type. Any ideas as to why this is happening?
Also, is there any way to change to font, and/or, color of the message output? I tried to change the background of the property grid cell and I understand that this is not possible to do.
Thank you.
Z
More of the code:
[
Description("Enter or select the wave file. If no extension, or a non .wav extension, is specified, the default extension .wav will be added to the filename."),
GridCategory("Sound"),
Gui.Design.DisplayName ("Input Sound"),
PathEditor.OfdParamsAttribute("Wave files (*.wav)|*.wav", "Select Audio File"),
Editor(typeof(PathEditor), typeof(System.Drawing.Design.UITypeEditor))
]
public string InputWavefile
{
get { return System.IO.Path.GetFileName(inputtWavefile); }
set
{
if (value != inputWavefile) // inputWavefile has been changed
{
// validate the input stringg
_inputWavefile = FileValidation.ValidateFile(value);
// assign validated value
inputWavefile = _inputWavefile;
}
}
}
My guess is that you've got a funky character at the start of inputFile which is confusing things - try looking at it in the debugger using inputFile.ToCharArray() to get an array of characters.
The string concatenation itself should be fine - it's how the value is being interpreted which is the problem, I suspect...
I'm guessing your filename looks something like this, C:\Folder\FileName.txt when you start out.
In your FileValidation.ValidateFile() method you
return "Error_" + InputFileName;
it now looks like this: Error_C:\Folder\FileName.txt.
So, when you run the line below,
get { return System.IO.Path.GetFileName( _inputWavefile ); }
it strips off the path and returns the filename only, FileName.txt.
Even when the filename is not valid, you are still running System.IO.Path.GetFileName() on it.
Assuming this is a PropertyGrid in winforms app. Then it's neither a string concatenation issue, nor PropertyGrid issue, as could be proven by the following snippet. So you need to look elsewhere in your code:
public partial class Form1 : Form {
PropertyGrid pg;
public Form1() {
pg = new PropertyGrid();
pg.Dock = DockStyle.Fill;
this.Controls.Add(pg);
var inputFile = "some fileName.txt";
var obj = new Obj();
obj.One = "Error_" + inputFile;
obj.Two = inputFile + "Error_";
pg.SelectedObject = obj;
}
}
class Obj {
public string One { get; set; }
public string Two { get; set; }
}

Categories

Resources