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'?
Related
I have a program in C# where I need to append all the data from the a text file to another text file, then the clear the first text file. Now I need some way to check if the data has been completely transferred and was successful and then display this information to the user in a MessageBox saying this was successful.
Here is what I am currently doing to append the data.
private void updateLog()
{
#region ifexists
if (!File.Exists(localLog + "A.txt"))
{
FileStream file = File.Create(localLog + "A.txt");
file.Close();
}
if (!File.Exists(localLog + "B.txt"))
{
FileStream file = File.Create(localLog + "B.txt");
file.Close();
}
#endregion
try
{
//reading files into input & output
using (Stream a_input = File.OpenRead(localLog + #"\A.txt"))
using (Stream b_input = File.OpenRead(localLog + #"\B.txt"))
using (Stream a_output = new FileStream(server + #"\A.txt", FileMode.Append, FileAccess.Write, FileShare.None))
using (Stream b_output = new FileStream(server + #"\B.txt", FileMode.Append, FileAccess.Write, FileShare.None))
{
//copying from input to output
a_input.CopyTo(a_output);
b_input.CopyTo(b_output);
copiedFlag = true; // I want some sort of flag to check, this is not much help
}
//clearing input
if (copiedFlag == true) // based on that flag I want to clear the 1st text, if the data is not copied then I do not want to clear the 1st text file
{
File.WriteAllText(localLog + #"\A.txt", string.Empty);
File.WriteAllText(localLog + #"\B.txt", string.Empty);
}
}
catch (Exception a)
{
System.Diagnostics.Debug.WriteLine("synchronization");
exceptionHandler();
}
}
All I'm doing is appending one file to another and then clearing the first file, but I want to make sure that the data is appended before I clear and loose it.
Your approach seems like overkill. Why not use System.IO.File.Copy method? You don't need to open streams to do a plain file copy.
I have a folder called data/ in my project that contains txt files.
I configured Build Action to resources to all files.
I tried these different ways:
method 1
var resource = Application.GetResourceStream(new Uri(fName, UriKind.Relative));
StreamReader streamReader = new StreamReader(resource.Stream);
Debug.WriteLine(streamReader.ReadToEnd());
method 2
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
string[] fileNames = myIsolatedStorage.GetFileNames("*.txt");
method 3
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamReader fileReader = new StreamReader(new IsolatedStorageFileStream(fName, FileMode.Open, isf)))
{
while (!fileReader.EndOfStream)
{
string line = fileReader.ReadLine();
al.Add(line);
Debug.WriteLine(line);
}
}
}
Now, i tried different ways to read files without success, why?
Where is the problem?
What's wrong with these methods?
fName is the name of the file.
It's necessary the full path data/filename.txt? It's indifferent...
please help me with this stupid issue,
thanks.
Your 2nd & 3rd approaches are wrong. When you include a text file locally in your app, you can't refer it via the IS. Instead, use this function, it will return the file content if found else it will return "null". It works for me, hope it works for you.
Note, if the file is set as content, the filePath = "data/filename.txt" but if it is set as resource it should be referred like this filePath = "/ProjectName;component/data/filename.txt". That may be why your 1st approach might have failed.
private string ReadFile(string filePath)
{
//this verse is loaded for the first time so fill it from the text file
var ResrouceStream = Application.GetResourceStream(new Uri(filePath, UriKind.Relative));
if (ResrouceStream != null)
{
Stream myFileStream = ResrouceStream.Stream;
if (myFileStream.CanRead)
{
StreamReader myStreamReader = new StreamReader(myFileStream);
//read the content here
return myStreamReader.ReadToEnd();
}
}
return "NULL";
}
I am able to do read/write/append operation on text file storing in isolated storage in WP7 application.
My scenario is that I am storing space seperated values in text file inside isolated storage.
So if I have to find for some particular line having some starting key then how to overwrite
value for that key without affecting the other line before and after it.
Example:
Key Value SomeOtherValue
*status read good
status1 unread bad
status2 null cantsay*
So if I have to change the whole second line based on some condition with key as same
status1 read good
How can I achieve this?
There are a number of ways you could do this, and the method you choose should be best suited to the size and complexity of the data file.
One option to get you started is to use the static string.Replace() method. This is crude, but if your file is only small then there is nothing wrong with it.
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("*status read good");
sb.AppendLine("status1 unread bad");
sb.AppendLine("status2 null cantsay*");
string input = sb.ToString();
var startPos = input.IndexOf("status1");
var endPos = input.IndexOf(Environment.NewLine, startPos);
var modifiedInput = input.Replace(oneLine.Substring(startPos, endPos - startPos), "status1 read good");
Console.WriteLine(modifiedInput);
Console.ReadKey();
}
}
If you store this information in text files then there won't be a way around replacing whole files. The following code does exactly this and might even be what you are doing right now.
// replace a given line in a given text file with a given replacement line
private void ReplaceLine(string fileName, int lineNrToBeReplaced, string newLine)
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
// the memory writer will hold the read and modified lines
using (StreamWriter memWriter = new StreamWriter(new MemoryStream()))
{
// this is for reading lines from the source file
using (StreamReader fileReader = new StreamReader(new IsolatedStorageFileStream(fileName, System.IO.FileMode.Open, isf)))
{
int lineCount = 0;
// iterate file and read lines
while (!fileReader.EndOfStream)
{
string line = fileReader.ReadLine();
// check if this is the line which should be replaced; check is done by line
// number but could also be based on content
if (lineCount++ != lineNrToBeReplaced)
{
// just copy line from file
memWriter.WriteLine(line);
}
else
{
// replace line from file
memWriter.WriteLine(newLine);
}
}
}
memWriter.Flush();
memWriter.BaseStream.Position = 0;
// re-create file and save all lines from memory to this file
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(fileName, System.IO.FileMode.Create, isf))
{
memWriter.BaseStream.CopyTo(fileStream);
}
}
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
ReplaceLine("test.txt", 1, "status1 read good");
}
And I agree with slugster: using SQLCE database might be a solution with better performance.
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);
I am trying to make a text file in memory, add some lines to it and at the end save the file in a text file. I can handle the savedialog part but I dont know how to get the text file from memory. Any help and tips will be appriciated.
What I am doing so far is:
//Initialize in memory text writer
MemoryStream ms = new MemoryStream();
TextWriter tw = new StreamWriter(ms);
tw.WriteLine("HELLO WORLD!");
tw.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!);
please note
I will call tw.WriteLine() add more lines in different places so I want to save this at end of program (so this shouldent be wrapped between something like using{} )
UPDATE
StringBuilder seems to be a more reliable option for doing this! I get strange cut-outs in my text file when I do it using MemoryStream.
Thanks.
I think your best option here would be to write to a StringBuilder, and when done, File.WriteAllText. If the contents are large, you might consider writing directly to the file in the first place (via File.CreateText(path)), but for small-to-medium files this should be fine.
var sb = new StringBuilder();
sb.AppendLine("HELLO WORLD!");
sb.AppendLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!");
File.WriteAllText(path, sb.ToString());
Or, something nigh-on the same as #Marc's answer, but different enough that I think it's worth putting out there as a valid solution:
using (var writer = new StringWriter())
{
writer.WriteLine("HELLO WORLD!");
writer.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!");
File.WriteAllLines(path, writer.GetStringBuilder().ToString());
}
Where path is a string representing a valid file system entry path, predefined by you somewhere in the application.
Assume your SaveFileDialog name is "dialog"
File.WriteAllBytes(dialog.FileName, Encoding.UTF8.GetBytes("Your string"));
or
var text = "Your string";
text += "some other text";
File.WriteAllText(dialog.FileName, text);
also in your own solution you can do this :
MemoryStream ms = new MemoryStream();
TextWriter tw = new StreamWriter(ms);
tw.WriteLine("HELLO WORLD!");
tw.WriteLine("I WANT TO SAVE THIS FILE AS A .TXT FILE!);
// just add this
File.WriteAllBytes(dialog.FileName, ms.GetBuffer());
Something like this.
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".text"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
using (FileStream file = File.CreateText(dlg.FileName)
{
ms.WriteTo(file)
}
}
I haven't worried about whether the file already exists but this should get you close.
You might need a ms.Seek(SeekOrgin.Begin, 0) too.
Another way of appending text to the end of a file could be:
if (saveFileDialog.ShowDialog() == DialogResult.OK) {
using (var writer = new StreamWriter(saveFileDialog.Filename, true)) {
writer.WriteLine(text);
}
}
supposing that text is the string you need to save into your file.
If you want to append new lines to that string in an easy way, you can do:
var sb = new StringBuilder();
sb.AppendLine("Line 1");
sb.AppendLine("Line 2");
and the resulting string will be sb.ToString()
If you already have a Stream object (in your example, a MemoryStream), you can do the same but replace the line:
using (var writer = new StreamWriter(saveFileDialog.Filename, true)) {
by
using (var writer = new StreamWriter(memoryStream)) {
Edit:
About wrapping the statements inside using:
Take in count that this is not a problem at all. In my first example, all you will have to do is to keep that StringBuilder object, and keep adding lines to it. Once you have what you want, just write the data into a text file.
If you are planning to write more than once to the text file, just clear the StringBuilder everytime you write, in order to not get duplicated data.