I want to be able to have a list of class objects (List<Class>) and be able to easily write and read to a text file.
In my older Console Applications and Windows Forms applications I used to use:
List<Class> _myList = ...
WriteToFile<List<Class>>("C:\\...\\Test.txt", Class _myList)
public static void WriteToFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
TextWriter writer = null;
try
{
var serializer = new XmlSerializer(typeof(T));
writer = new StreamWriter(filePath, append);
serializer.Serialize(writer, objectToWrite);
}
finally
{
if (writer != null)
writer.Close();
}
}
However this does not work in a UWP application and I have to use StorageFolder and StorageFile which works fine for writing simple text to a file like this:
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file= await storageFolder.GetFileAsync("Test.txt");
await FileIO.WriteTextAsync(sampleFile, "Example Write Text");
But I want to be able to use the more advanced functionality of XmlSerializer along with StreamWriter to write lists of classes to a file within my UWP application.
How can I do this?
You can use the Stream-based versions the methods you use, for example StreamWriter has a constructor which takes a System.IO.Stream instance.
To get a System.IO.Stream from a StorageFile, you can use the OpenStreamForWriteAsync and OpenStreamForReadAsync extension methods, which are in the System.IO namespace on UWP:
//add to the top of the file
using System.IO;
//in your code
var stream = await myStorageFile.OpenStreamForWriteAsync();
//do something, e.g.
var streamWriter = new StreamWriter(stream);
Related
I am developing an application for the HoloLens 2 with Unity. I am still very confused how to connect the UWP environment and the .NET API.
I want to read text files (.txt) as well as binary files (.raw). When working on the Hololens (UWP environment) i use from Windows.Storage the FileOpenPicker(). I have currently coded the processing of the files so that I can test them in the Unity editor (.NET environment). Therefore i use File.ReadAllLines(filePath) to get the txt File and get every line as String, for the Binary Files i use FileStream fs = new FileStream(filePath, FileMode.Open) and BinaryReader reader = new BinaryReader(fs). The Method File.ReadAllLines() from System.IO does not work on the Hololens and i imagine the File stream and the Binary reader will not work as well.
So my Questions is how can i load the data when using the Hololens through the specific UWP API and then use the System.IO API for the rest?
Example of picking files (to get path for later readers):
#if !UNITY_EDITOR && UNITY_WSA_10_0
UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
{
var filepicker = new FileOpenPicker();
filepicker.FileTypeFilter.Add("*");
var file = await filepicker.PickSingleFileAsync();
UnityEngine.WSA.Application.InvokeOnAppThread(() =>
{
path = (file != null) ? file.Path : "Nothing selected";
name = (file != null) ? file.Name : "Nothing selected";
Debug.Log("Hololens 2 Picker Path = " + path);
}, false);
}, false);
#endif
#if UNITY_EDITOR
OpenFileDialog openFileDialog1 = new OpenFileDialog();
path = openFileDialog1.FileName;
...
#endif
EDIT:
To make it more clear i have another class which uses the file path (from the picker) and reads the file, depending on the extension (.txt, .raw), as text file or binary file with the help of the System.IO methods.
// For text file
string[] lines = File.ReadAllLines(filePath);
string rawFilePath = "";
foreach (string line in lines)
{
}
// For binary file
FileStream fs = new FileStream(filePath, FileMode.Open);
BinaryReader reader = new BinaryReader(fs);
But on the Hololens 2 the File.ReadAllLines(filePath) throws a DirectoryNotFoundException: Could not find a part of the path Exception. Can i use the Windows.Storage.StorageFile and change it so it works with the code which uses the System.IO methods?
I think i found an Answer and i hope it helps others with the same problem:
#if !UNITY_EDITOR && UNITY_WSA_10_0
public async Task<StreamReader> getStreamReader(string path)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(path);
var randomAccessStream = await file.OpenReadAsync();
Stream stream = randomAccessStream.AsStreamForRead();
StreamReader str = new StreamReader(stream);
return str;
}
#endif
With this code i can get a stream from an Windows StorageFile and generate a StreamReader or a BinaryReader through which i can use the rest of my calculations written with System.IO.
In windows phone 8.1
i want to use streamwriter in text, and appending text to file end.
But the text is appended to the beginning of the file.
how to appending text to file end?
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(#"ms-appx:///input_category_list.txt"));
using (StreamWriter sWrite = new StreamWriter(await file.OpenStreamForWriteAsync(), System.Text.UTF8Encoding.UTF8))
{
sWrite.WriteLine(write_category_box.Text);
await sWrite.FlushAsync();
}
There's no need for StreamWriter in Windows Runtime, you can use FileIO class (which is easier):
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(#"ms-appx:///input_category_list.txt"));
await FileIO.AppendTextAsync(file, write_category_box.Text, UnicodeEncoding.Utf8);
change your code to this:
new StreamWriter(await file.OpenStreamForWriteAsync(),System.Text.UTF8Encoding.UTF8,true))
if you overrride StreamWriter constructor, as true, this will set to append text. Otherwise overwrite it.
I'm new to C# and Windows Phone developing, I need to do app for school project.
I have simple class, and I want to save it to have access later, on next start of application.
What is the best (and easiest) method to do that? Using file, database or some other application memory?
Here is my class:
public class Place
{
private string name;
private string description;
private int distance;
private bool enabled;
private GeoCoordinate coordinates;
}
I need to store multiple instances of class.
There is no "best" way to do it; it depends on how you're going to use it.
A simple way is to use serialization, to XML, JSON, binary or whatever you want. I personally like JSON, as it's very lightweight and easy to read for a human. You can use the JSON.NET library to serialize objects to JSON.
For instance, if you want to serialize a collection of Place to a file, you can do something like that:
static async Task SavePlacesAsync(ICollection<Place> places)
{
var serializer = new JsonSerializer();
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync("places.json", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenStreamForWriteAsync())
using (var writer = new StreamWriter(stream))
{
serializer.Serialize(writer, places);
}
}
And to read it back from the file:
static async Task<ICollection<Place>> LoadPlacesAsync()
{
try
{
var serializer = new JsonSerializer();
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync("places.json");
using (var stream = await file.OpenStreamForReadAsync())
using (var reader = new StreamReader(stream))
using (var jReader = new JsonTextReader(reader))
{
return serializer.Deserialize<ICollection<Place>>(jReader, places);
}
}
catch(FileNotFoundException)
{
return new List<Place>();
}
}
I think the easiest way to make persistent your object is to store them in a file. However this is not the best way due to the time spent in IO operations, low security, etc.
Here you have a nice example:
How to quickly save/load class instance to file
I try to create a text file and write some data to it. I am using the following code:
public void AddNews(string path,string News_Title,string New_Desc)
{
FileStream fs = null;
string fileloc = path + News_Title+".txt";
if (!File.Exists(fileloc))
{
using (fs = new FileStream(fileloc,FileMode.OpenOrCreate,FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fileloc))
{
sw.Write(New_Desc);
}
}
}
}
I got this exception in stream writer:
The process cannot access the file '..............\Pro\Content\News\AllNews\Par.txt'
because it is being used by another process.
Text file is created, but I can't write to it.
When you create your StreamWriter object, you're specifying the same file that you already opened as a FileStream.
Use the constructor overload of StreamWriter that accepts your FileStream object, instead of specifying the file again, like this:
using (StreamWriter sw = new StreamWriter(fs))
I would simply do this:
public void AddNews(string path, string News_Title, string New_Desc)
{
string fileloc = Path.Combine(path, News_Title+".txt");
if (!File.Exists(fileloc)) {
File.WriteAllText(fileloc, New_Desc);
}
}
Note that I use Path.Combine as a better way to create paths, and File.WriteAllText as a simple way of creating a file and writing something to it. As MSDN says:
If the target file already exists, it is overwritten.
so we first check if the file already exists, as you did. If you want to overwrite its contents, just don't check and write directly.
The issue could be that the file is open or in use. Consider checking if the file is open before writing to it...
public bool IsFileOpen(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
// Is Open
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//Not Open
return false;
}
Good Luck!
using (TextWriter tw = new StreamWriter(path, true))
{
tw.WriteLine("The next line!");
}
I'm trying to open a stream to a file.
First I need to save a file to my desktop and then open a stream to that file.
This code works well (from my previous project) but in this case, I don't want to prompt the user to pick the save location or even the name of the file. Just save it and open the stream:
Stream myStream;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
if ((myStream = saveFileDialog1.OpenFile()) != null)
{
PdfWriter.GetInstance(document, myStream);
Here's my code for the newer project (the reason for this question):
namespace Tutomentor.Reporting
{
public class StudentList
{
public void PrintStudentList(int gradeParaleloID)
{
StudentRepository repo = new StudentRepository();
var students = repo.FindAllStudents()
.Where(s => s.IDGradeParalelo == gradeParaleloID);
Document document = new Document(PageSize.LETTER);
Stream stream;
PdfWriter.GetInstance(document, stream);
document.Open();
foreach (var student in students)
{
Paragraph p = new Paragraph();
p.Content = student.Name;
document.Add(p);
}
}
}
}
Use Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) to get the desktop directory.
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
"MyFile.pdf");
using(var stream = File.OpenWrite(fileName))
{
PdfWriter.GetInstance(document, stream);
}
// However you initialize your instance of StudentList
StudentList myStudentList = ...;
using (FileStream stream = File.OpenWrite(#"C:\Users\me\Desktop\myDoc.pdf")) {
try {
myStudentList.PrintStudentList(stream, gradeParaleloID);
}
finally {
stream.Close();
}
}
You should pass the stream into your method:
public void PrintStudentList(Stream stream, int gradeParaleloID) { ... }
EDIT
Even though I hard coded a path above, you shouldn't do that, use something like this to get the path to your desktop:
Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
If this is a local (e.g. Windows/console) application just make the stream a FileStream to whatever path you want (check this for info on how to get the desktop folder path). If the user running the application has write permitions to that file it will be created/saved there.
If this is a web (e.g. ASP.Net) application you won't be able to save the file directly in the client machine without prompting the user (for security reasons).
Stream myStream = new FileStream(#"c:\Users\[user]\Desktop\myfile.dat", FileMode.OpenOrCreate);
Your FileMode may differ depending on what you're trying to do. Also I wouldn't advise actually using the Desktop for this, but that's what you asked for in the question. Preferably, look into Isolated Storage.