I have a DataGridView which displays a list of rail cars and has several buttons for manipulating the list (Add, Edit, Delete, Save). The contents of the DGV come from an XML file and are saved back to the same file when the Save button is clicked. All functions of this form work perfectly with the exception of the Delete button. When I delete a rail car from the list and click Save, it takes the "deleted" row and re-appends it to the XML file in a very weird way (picture below).
Here is the code for the form (I'm only including the Save & Delete buttons and XML handling for ease of reading):
public partial class SimulatedTrainEditor : Form
{
//fileName and XML variables for serialization/deserialization
const string fileName = "SimulatedTrain1.xml";
XmlSerializer xml = new XmlSerializer(typeof(BindingList<SimulatedTrain>));
//Create BindingList object to hold XML data
public BindingList<SimulatedTrain> NewSimulatedTrain = new BindingList<SimulatedTrain>();
public bool WereChangesMade;
public SimulatedTrainEditor()
{
InitializeComponent();
LoadXML();
this.dataGridViewSimulatedTrainEditor.DataSource = NewSimulatedTrain;
this.dataGridViewSimulatedTrainEditor.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.dataGridViewSimulatedTrainEditor.AllowUserToAddRows = false;
this.WereChangesMade = false;
this.buttonSaveXML.Enabled = false;
}
public void LoadXML()
{
try
{
using (var fs = new FileStream(fileName, FileMode.Open))
{
NewSimulatedTrain = (BindingList<SimulatedTrain>)xml.Deserialize(fs);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message, ex);
}
}
private void buttonRemoveRailCar_Click(object sender, EventArgs e)
{
var currentRow = this.dataGridViewSimulatedTrainEditor.CurrentRow;
if (currentRow != null)
{
this.NewSimulatedTrain.RemoveAt(currentRow.Index);
this.WereChangesMade = true;
this.buttonSaveXML.Enabled = true;
}
}
private void buttonSaveXML_Click(object sender, EventArgs e)
{
//are there any changes?
if (WereChangesMade)
{
//save the file if changes
using (var fs = new FileStream(fileName, FileMode.OpenOrCreate))
{
xml.Serialize(fs, this.NewSimulatedTrain);
}
//Disable the SaveXML button when it's clicked to look for new edits after each save
this.buttonSaveXML.Enabled = false;
}
}
}
And here are screenshots of before and after I delete a row (this is just the bottom portion of the XML):
Before:
After (the red bit should be the end of the XML file):
You can see it tries to add another closing ArrayOfSimulatedTrain tag to the end after it throws in the row data that should have been deleted. I am still getting use to working with XML files, but in the few instances I've done this type of work before, I've never run into this particular issue.
Using FileStream in FileMode.OpenOrCreate mode does not wipe the content of file before writing.
Editing the XML changes the length of the content that will be written in the file. If the new XML is shorter, you will have some leftovers at the end of the file. From the MSDN :
If you overwrite a longer string (such as “This is a test of the OpenWrite method”) with a shorter string (such as “Second run”), the file will contain a mix of the strings (“Second runtest of the OpenWrite method”).
You need to change the FileMode of the stream to FileMode.Create to overwrite the whole file :
//save the file if changes
using (var fs = new FileStream(fileName, FileMode.Create))
{
xml.Serialize(fs, this.NewSimulatedTrain);
}
Related
Been looking through other people's answers and nothing seems to work.
Here is my code:
public void TaskOnClick() //getting multi-values
{
foreach (string inputJson in File.ReadLines("Assets/Text/multi-import.txt"))
{
string temperature = GetTemperatureByRegex(inputJson);
Debug.Log(temperature);
string filename = "Assets/Text/TEMP/multi-export.txt";
{
using (StreamWriter writeFile = new StreamWriter(filename, false))
{
writeFile.AutoFlush = true;
Console.SetOut(writeFile);
writeFile.WriteLineAsync(temperature.ToString());
}
}
}
}
The idea is that my parsing script gets my data and then streamwriter writes the data to a txt file. Problem is that streamwriter keeps appending the txt file instead of overwriting the file.
Whenever I try to use filestream it overwrites the file, yes, but only the first line of the data gets written, no matter what I tried.
My username speaks for itself...
What you do wrong is creating StreamWriter inside a loop. If you provide an overwrite settings it will only write 1 line.
public void TaskOnClick() //getting multi-values
{
string filename = "Assets/Text/TEMP/multi-export.txt";
using (StreamWriter writeFile = new StreamWriter(filename, false))
{
foreach (string inputJson in File.ReadLines("Assets/Text/multi-import.txt"))
{
string temperature = GetTemperatureByRegex(inputJson);
Debug.Log(temperature);
writeFile.AutoFlush = true;
Console.SetOut(writeFile);
writeFile.WriteLine(temperature.ToString());
}
}
}
But there is a shorter way of doing this with the help of LINQ.
public void TaskOnClick() //getting multi-values
{
string filename = "Assets/Text/TEMP/multi-export.txt";
var tempratures = File.ReadAllLines("Assets/Text/multi-import.txt")
.Select(GetTemperatureByRegex).ToArray();
File.WriteAllLines(filename,tempratures); // it creates a new file or overwrites
}
I have to state that above method may be dangerous if input file is too large. Because it reads entire file into memory.
Why don’t you just delete the file before opening the stream writer?
if(File.Exists(filename)){
File.Delete(filename);
}
//here whatever you need to do next
How do i read and sort a text file
sorry if this is an easy question I'm new to coding. I've tried many online solution but none seems to fix my problem:
namespace Login_but_it_hopefully_works
{
public partial class Leaderboard : Form
{
string Line = "";
private string filepath1 = #"Compdetails.txt";
FileStream readerStream = new FileStream("Compdetails.txt", FileMode.Open);
string[] content = null;
public Leaderboard()
{
InitializeComponent();
}
public object ListReadFile { get; private set; }
private void bttn_load_Click(object sender, EventArgs e)
{
string[] content = null;
//Read the content
using (StreamReader CompTXT = File.OpenText(filepath1))
{
content = CompTXT.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
//Remove the entries in the file
readerStream.SetLength(0);
}
FileStream writerStream = new FileStream(#"Desktop\Source\text.txt", FileMode.OpenOrCreate);
using (StreamWriter writer = new StreamWriter(writerStream))
{
//Sort the content and write back to the same file
Array.Sort(content);
writer.Write(string.Join(Environment.NewLine, content));
}
}
}
}
The error is:
Additional information: The process cannot access the file
'E:\CS\Login\Login but it hopefully works\bin\Debug\Compdetails.txt'
because it is being used by another process and the line is " using
(StreamReader CompTXT = File.OpenText(filepath3))"
Remove the 2 lines involving readerStream. They are not accomplishing what do you think they are, but they are causing that error. :-) Your next task will be to overwrite the file rather than append to it.
To elaborate on the cause of the error: having that field declared in the class and initialized by opening a stream causes the file to be locked for as long as an instance of the class exists. When you then call the button event method and try to open another stream with another lock on the same file, an exception results.
When the app runs for the first time I'm adding items to a text file like so:
StringBuilder sb = new StringBuilder(); // Use a StringBuilder to construct output.
var store = IsolatedStorageFile.GetUserStoreForApplication(); // Create a store
store.CreateDirectory("testLocations"); // Create a directory
IsolatedStorageFileStream rootFile = store.CreateFile("locations.txt"); // Create a file in the root.
rootFile.Close(); // Close File
string[] filesInTheRoot = store.GetFileNames(); // Store all files names in an array
Debug.WriteLine(filesInTheRoot[0]); // Show first file name retrieved (only one stored at the moment)
string filePath = "locations.txt";
if (store.FileExists(filePath)) {
Debug.WriteLine("Files Exists");
StreamWriter sw =
new StreamWriter(store.OpenFile(filePath,
FileMode.Open, FileAccess.Write));
Debug.WriteLine("Writing...");
sw.WriteLine("Chicago, IL;");
sw.WriteLine("Chicago, IL (Q);");
sw.WriteLine("Dulles, VA;");
sw.WriteLine("Dulles, VA (Q);");
sw.WriteLine("London, UK;");
sw.WriteLine("London, UK (Q);");
sw.WriteLine("San Jose, CA;");
sw.WriteLine("San Jose, CA (Q);");
sw.Close();
Debug.WriteLine("Writing complete");
}
I can then view this data in a ListPicker using the follow code when a button is pressed, again all works well:
private void locChoice(object sender, RoutedEventArgs e)
{
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
string filePath = "locations.txt";
if (store.FileExists(filePath))
{
Debug.WriteLine("Files Exists");
try
{
string fileData;
using (IsolatedStorageFileStream isoStream =
new IsolatedStorageFileStream("locations.txt", FileMode.Open, store))
{
using (StreamReader reader = new StreamReader(isoStream))
{
fileData = reader.ReadToEnd();
}
}
testLocationPicker.ItemsSource = fileData.Split(';');
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
testLocationPicker.Open();
}
I now want to add to the text file programmatically, which I'm doing like so, once users have filled in some text blocks:
StringBuilder sb = new StringBuilder(); // Use a StringBuilder to construct output.
var store = IsolatedStorageFile.GetUserStoreForApplication(); // Create a store
string[] filesInTheRoot = store.GetFileNames(); // Store all files names in an array
Debug.WriteLine(filesInTheRoot[0]); // Show first file name retrieved (only one stored at the moment)
string filePath = "locations.txt";
if (store.FileExists(filePath))
{
Debug.WriteLine("Files Exists");
StreamWriter sw =
new StreamWriter(store.OpenFile(filePath,
FileMode.Open, FileAccess.Write));
Debug.WriteLine("Writing...");
sw.WriteLine(locationName + ";"); // Semi Colon required for location separation in text file
sw.Close();
Debug.WriteLine(locationName + "; added");
Debug.WriteLine("Writing complete");
}
However, when I now go back to the previous page and click the button to view the entries in a ListPicker it turns out strange. The latest entry appears at the top with a large gap to the second place in the list. Adding another entry on top of that seems to hide the last entry.
The screenshot below should have to entries above the first "Chicago" entry. There should be a second Chicago entry that appears to have disappeared also.
Is there any way to browse to the created text file on the phone and see exactly how the data is laid out? This could give a clue.
Upon further investigation it appears when I write another line it is overwriting the existing text, rather than adding a new line. Any idea how to stop this?
I found some more documentation related to appending a file, which confirms my suspicion that the data was being overwritten.
The method I used when adding data now looks like this:
// ----------------------------------------------------------------
// Write the friend name to the locations text file upon submission
// ----------------------------------------------------------------
StringBuilder sb = new StringBuilder(); // Use a StringBuilder to construct output.
var store = IsolatedStorageFile.GetUserStoreForApplication(); // Create a store
string[] filesInTheRoot = store.GetFileNames(); // Store all files names in an array
Debug.WriteLine(filesInTheRoot[0]); // Show first file name retrieved (only one stored at the moment)
byte[] data = Encoding.UTF8.GetBytes(locationName + ";");
string filePath = "locations.txt";
if (store.FileExists(filePath))
{
using (var stream = new IsolatedStorageFileStream(filePath, FileMode.Append, store))
{
Debug.WriteLine("Writing...");
stream.Write(data, 0, data.Length); // Semi Colon required for location separation in text file
stream.Close();
Debug.WriteLine(locationName + "; added");
Debug.WriteLine("Writing complete");
}
}
Another Stack Overflow post helped me with the solution that didn't appear during my first search:
Does IsolatedStorage File.Append mode has an error with the the '\n'?
I am making simple tool for manipulating images in a database. I want to show the output result in a txt file and because the outcome may be different each time, I want the file to be rewritten with the fresh data every time the data is executed.
Also I want (if possible) to use some default location where the txt file will be created even though I have an App.Config file and that's also an option.
The problem I am having is with this code:
string Resultfile =
System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +
"\\PictureStatus.txt";
FileStream strm = new FileStream(Resultfile , FileMode.Create);
TextWriter tw = new StreamWriter(strm);
This populates the PictureStatus.txt only once and then I get the same text over and over again. I noticed that if I use some random destination the file is updated. Not sure if it's just random behavior or have something to do with using MyDocuments, but what I need is a way to be sure that I'll rewrite the file with the new data each time, and if possible, use some default destination that will work for other people.
You can try something like this
public partial Form2 : Form
{
public string path = Environment.CurrentDirectory + "/" + "Name.txt";
public Form2()
{
InitializeComponent();
if (!File.Exists(path))
{
File.Create(path);
}
}
private void button2_Click(object sender, EventArgs e)
{
using (StreamWriter sw = new StreamWriter(path, true))
{
sw.WriteLine("This text will be writen in the txt file", true);
sw.Close();
}
}
}
I have add to the button, when I pressed it will be written in the next line every time. If you remove "true" from code, it will be overwritten every time.
I am currently creating a windows phone 7 application. How do I transform all the values of an array to textfile so I can print out all the values stored in that particular array inside another page listbox, and then store inside an isolated storage.
Thanks! :(
I tried this method but it doesn't work.
For ViewList.xaml.cs
private void addListBtn_Click(object sender, RoutedEventArgs e)
{
//Obtain the virtual store for application
IsolatedStorageFile myStore = IsolatedStorageFile.GetUserStoreForApplication();
//Create a new folder and call it "ImageFolder"
myStore.CreateDirectory("ListFolder");
//Create a new file and assign a StreamWriter to the store and this new file (myFile.txt)
//Also take the text contents from the txtWrite control and write it to myFile.txt
StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream("ListFolder\\myFile.txt", FileMode.OpenOrCreate, myStore));
writeFile.WriteLine(retrieveDrinksListBox);
writeFile.Close();
}
FavouriteList.xaml.cs
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
//Obtain a virtual store for application
IsolatedStorageFile myStore = IsolatedStorageFile.GetUserStoreForApplication();
//This code will open and read the contents of retrieveDrinksListBox
//Add exception in case the user attempts to click “Read button first.
StreamReader readFile = null;
try
{
readFile = new StreamReader(new IsolatedStorageFileStream("ListFolder\\myFile.txt", FileMode.Open, myStore));
string fileText = readFile.ReadLine();
if (fileText != "")
{
listNumberListBox.Items.Add("List 1");
}
//The control txtRead will display the text entered in the file
listNumberListBox.Items.Add(fileText);
readFile.Close();
}
catch
{
MessageBox.Show("Need to create directory and the file first.");
}
You must write away the serialized items/data of the listbox, not the listbox itself.
When reading them again, you must deserialize them.The BinaryFormatter example on MSDN has code samples showing you how to write away an object to a (file)stream and how to recover the object again from that same stream.
If you want to display contents of your file (say, lines) in listbox, read entire file content at once and split the lines:
string fileText = readFile.ReadToEnd();
string[] lines = fileText.Split(Enviroment.NewLine.ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);
listNumberListBox.Items.AddRange(lines);
Other way around is similar, fetch items from your listbox, by joining them with new line, and dump at once to file:
string fileContents = string.Join(Environment.NewLine,
retrieveDrinksListBox.Items.Cast<string>());
writeFile.WriteLine(fileContents);