I have a problem with the XmlTextWriter class, I can't write to a file.
It is a console application I'm creating and the function looks like this.
private void WriteXML()
{
Console.WriteLine("Writing");
using (XmlTextWriter writer = new XmlTextWriter("DataW.xml", System.Text.Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteComment("This is a comment");
writer.WriteStartElement("WeeklyReview");
writer.WriteStartElement("DateTime");
writer.WriteStartAttribute("DateTime","09/04/2018 05:00");
writer.WriteElementString("Activity", "At Theodor");
writer.WriteElementString("Social", "Not Theodor,Theodor");
}
}
The result I'm getting is just a file with nothing in it. And in VS 2017 the file is shown with a white background and nothing in it.
The file I'm writing to is in the solution explorer and located in the same place as the file I'm reading from (which works).
I'm guessing the issue you're seeing is that the XML file created is blank or incomplete. If so, add a using statement around your code like so:
using (XmlTextWriter writer = new XmlTextWriter("DataW.xml", System.Text.Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteComment("This is a comment");
writer.WriteStartElement("Weekly Review"); //NB: A space in an element name!
writer.WriteStartElement("DateTime");
writer.WriteStartAttribute("09/04/2018 05:00"); //NB: a value given as an attribute name (consider: WriteAttributeString)!
writer.WriteElementString("Activity", "At Theodor");
writer.WriteElementString("Social", "Not Theodor,Theodor");
}
The reason for the issue is the methods you're calling write to an underlying stream rather than to the file system. To ensure that data is written to the file system you need to call the Flush method. Flush is called automatically when the writer is closed/disposed (but not when it's finalized). The using statement ensures that your writer is always disposed of correctly, so will ensure that your stream is flushed to disk.
For any other issues, you'd likely have an exception thrown (e.g. were there file access issues writing to the target location). If you're receiving an exception, please share that message and we can recommend a solution for that.
ps. The XML created by this is given below / it's not valid XML, so you'll have other issues down the line. I'll leave those for you to resolve, or for you to ask as another question should you have issues there. In the meantime, you can get some hints from the example in the documentation: https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmltextwriter.writestartattribute?view=netframework-4.7.2
<?xml version="1.0" encoding="utf-8"?>
<!--This is a comment-->
<Weekly Review>
<DateTime 09/04/2018 05:00="">
<Activity>At Theodor</Activity>
<Social>Not Theodor,Theodor</Social>
</DateTime>
</Weekly Review>
I know the Question is old, but in VB.net i got the same result.
I had to call XmlTextWriter.Flush() at the End to get Content in my File.
Related
I created a class called Shipment which has the following static method:
public static void WriteShipment(Shipment s, string path)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
XmlWriter w = XmlWriter.Create(path, settings);
w.WriteStartDocument();
w.WriteStartElement("Shipment");
w.WriteStartElement("id");
w.WriteString(s.id);
w.WriteEndElement();
Address.WriteAddress(s.from, path);
Address.WriteAddress(s.to, path);
Date.WriteDate(s.receiveDate, path);
Date.WriteDate(s.deliverDate, path);
w.WriteStartElement("sum");
w.WriteValue(s.sum);
w.WriteEndElement();
w.WriteStartElement("currency");
w.WriteString(s.currency);
w.WriteEndElement();
w.WriteStartElement("paid");
w.WriteValue(s.paid);
w.WriteEndElement();
w.WriteEndElement();
w.WriteEndDocument();
w.Close();
}
I'm trying to write a method which receives an instance of the Shipment class and creates an XML file with its details.
Some of Shipment's fields are of type Address and Date, which are other classes I created. They also have static methods which write the details of an instance, received as a parameter, into an XML file.
The WriteAddress and WriteDate methods work perfectly well, but when I try to invoke them inside the WriteShipment method, I get the following exception during run-time -
"the process cannot access file because it is used by another process"
I figured out it happens because WriteAddress and WriteDate are trying to write into the same file WriteShipment already writes into (since they all share the same path).
Is there a way to overcome this? Any other solution I've tried proved to be futile or caused other problems.
The problem you are seeing is likely because the WriteAddress and WriteDate methods are attempting to open the file that is already opened.
When you make the call to XmlWriter.Create, the file is being 'locked' such that it can only be written to using the w variable, and it remains locked until you call w.Close().
Your best option would be to pass the w variable as an argument to the WriteAddress and WriteDate methods and that to write to the file.
Also, as a suggestion, consider putting your code into a using block. That way, if any of the methods throw an exception, you won't be left with the file still locked.
There are many ways to fix this. Here are some suggestions.
Close the XmlWriter in WriteShipment before you execute the WriteDate and WriteAddress methods. Reopen it after you're done
Instead of opening and writing to the file in WriteData/Address just return a string and then write it to the file in WriteShipment. Is there any case where you need to write directly using WriteData/Address, and not as part through the WriteShipment method?
I have developed a website in asp.net mvc that reads from a xml-file to display some data. This file is regularly updated by my backend process that builds this xml-file and finally uploads it to my webhost via ftp.
This have been working fine, but in the last week or so I have gotten into a problem. I get the asp.net exception "file is being used by another process". I have no clue what this can be, and I find it very odd. I haven't even changed anything in my code for some months now.
Below you will find a typical method that I use for serializing my xml-file:
public static IEnumerable<FStreamObject> GetStreams()
{
using (FileStream fs = new FileStream(HttpRuntime.AppDomainAppPath+"/ff.xml", FileMode.Open))
{
XmlReader ffXML = XmlReader.Create(fs);
XmlSerializer ser = new XmlSerializer(typeof(FXmlModel));
var sList = (FXmlModel)ser.Deserialize(ffXML);
fs.Close();
return sList.FSObjectList.OrderByDescending(x => x.Cash);
}
}
I guess the other process which updates the content of your file still has a lock on this file. So you may need to fix the code of that to make sure you are releasing any locks /connection to this file once you are done with the file operations.
The problem could be that an Exception is being thrown before the fs.Close() invocation.
Try using a try-catch-fianlly and put the fs.Close() in the finally block.
Also have in mind the Close() method is not destroying the object immediately, you could also try using Dispose() to be sure the reference is being cleaned from memory.
Hope it helps!
For the last couple of hours I was struggling with LINQ to XML on Windows Phone 7. I simply just want to add new element to an existing XML file.
XElement newItem = new XElement("item",new XAttribute("id",3),
new XElement("content","Buy groceries"),
new XElement("status","false"));
IsolatedStorageFile isFile = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = new IsolatedStorageFileStream("/Items.xml", System.IO.FileMode.Open, isFile);
XDocument loadedDoc = XDocument.Load(stream);
loadedDoc.Add(newItem);
loadedDoc.Save(stream);
Generally I'm experiencing very weird behavior. Sometimes I am getting an error "Operation not permitted on IsolatedStorageFileStream.". Sometimes it is "Root element is missing" and sometimes it is "Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it." If, for example, I would change System.IO.FileMode.Open to Create I would get "Root element is missing" but apart from that there doesn't seem to be any pattern according to which error occurs.
It all seems like its my XML file which causes the problem:
<?xml version="1.0" encoding="utf-8" ?>
<items>
<item id="1">
<content>Get groceries</content>
<status>false</status>
</item>
<item id="2">
<content>Wash your car</content>
<status>true</status>
</item>
</items>
It doesn't get any simpler than that and I am absolutely sure I don't have any white spaces before the declaration in the actual XML file.
And to make it all even more weird I have downloaded little sample application that uses the same technique of writing to XML file. When I try to run it I am getting a very familiar error:
Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it.
Here is link to that thread: http://mobileworld.appamundi.com/blogs/petevickers/archive/2010/12/06/windows-phone-7-linq-to-xml-corruption.aspx/
Yesterday I installed Windows Phone SDK 7.1 BETA. Could that be causing the problem?
It seems like the problem is with locating xml file in isolated storage. I have created completely new project and new xml file inside.
Thats the only code I have:
// Constructor
public MainPage()
{
InitializeComponent();
var isFile = IsolatedStorageFile.GetUserStoreForApplication();
var stream = isFile.OpenFile("file.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
}
I'am still getting: Operation not permitted on IsolatedStorageFileStream. I have tried going into properties of file.xml changing Built action and copy to output directory but that didn't work. I tried adding:
isFile.Dispose();
I also tried adding conditional statement:
if (isFile.FileExists("file.xml"))...
But he couldn't find the file.
I have never been so stuck in my life. Please advice me what else can i try.
You're trying to save to the same stream you loaded from - but without "rewinding" it to the start. I don't know whether isolated storage streams are seekable, but you can try just changing the code to:
XDocument loadedDoc = XDocument.Load(stream);
loadedDoc.Add(newItem);
stream.Position = 0;
loadedDoc.Save(stream);
Note that while we don't need to reset the size of stream in this case as we're adding content, in other cases you might need to do so in order to avoid "leftover" bits at the end of the file.
Alternatively, load the document and close the stream, then open up a new stream to the same file. Note that you should use using statements to close the streams after each use, e.g.
using (var isFile = IsolatedStorageFile.GetUserStoreForApplication())
{
XDocument loadedDoc;
using (var stream = isFile.OpenFile("/Items.xml", FileMode.Open))
{
loadedDoc = XDocument.Load(stream);
}
loadedDoc.Add(newItem);
using (var stream = isFile.OpenFile("/Items.xml", FileMode.Create))
{
loadedDoc.Save(stream);
}
}
So I'm writing a C# app that has a couple of XML files added as resources. I read from these XML files to populate objects in the code using XML serialization and it works perfectly. So I can access the files like so (I've left some code out, just have the important bits):
using TestApp.Properties;
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
StringReader sr = new StringReader(Resources.Maps);
mapTiles = (MapTiles)serializer.Deserialize(sr);
Now however, I'd like to do the opposite. I'd like to take some data and write it to these XML resource files. However, I seem to be running into trouble with this aspect and was hoping someone could see something I'm messing up or let me know what I need to do? Here's what I'm trying to do:
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
TextWriter writer = new StreamWriter(Resources.Maps);
serializer.Serialize(writer, tempGroup);
writer.Close();
When I run this code though, I get an error on the 2nd line that says ArgumentException was unhandled - Empty path name is not legal.
So if anyone has any thoughts I would greatly appreciate some tips. Thanks so much.
The exception is being raised because you are passing Resources.Maps into StreamWriter. StreamWriter is handling this as a string and assuming it is file path for the stream. But the file path is empty so it is throwing an exception.
To fix out the StreamWriter line you could specify a local temporary file instead of Resources.Maps or use StringWriter with the default constructor e.g. new StringWriter().
If you are writing .resx files then ResXResourceWriter is the class you need. It will also handle your stream writing too. See http://msdn.microsoft.com/en-us/library/system.resources.resxresourcewriter.aspx and http://msdn.microsoft.com/en-us/library/ekyft91f.aspx. The second page has examples on how to use the class but breifly you would call something like this:
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
using (StringWriter stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, tempGroup);
using (ResXResourceWriter resourceWriter = new ResXResourceWriter("~/App_GlobalResources/some_file.resx"))
{
resourceWriter.AddResource("Maps", stringWriter.ToString());
}
}
If you want to write out an assembly that has a dynamically created resource in it the you can emit a new assembly. In that case have a look here http://msdn.microsoft.com/en-us/library/8ye65dh0.aspx.
The StreamWriter constructor is throwing the exception because Resources.Maps is an empty string.
Check out the documentation on MSDN:
http://msdn.microsoft.com/en-us/library/fysy0a4b.aspx
Hmm, after trying some other things and doing even more research it appears that the problem is that you cannot write to a resource that is part of the application. Something to do with the resource being written into the assembly and therefore it's not writable. So I'll have to modify my approach and write the output to a different file.
Unless of course anyone does know differently. This is just what I've discovered so far. Thanks to those who had some ideas though, much appreciated.
I'm currently exporting a database table with huge data (100000+ records) into an xml file using XmlTextWriter class and I'm writing directly to a file on the physical drive.
_XmlTextWriterObject = new XmlTextWriter(_xmlFilePath, null);
While my code runs ok, my question is that is it the best approach? Should I instead write the whole xml in memory stream first and then write the xml document in physical file from memory stream? And what are the effects on memory/ performance in both cases?
EDIT
Sorry that I could not actually convey what I meant to say.Thanks Ash for pointing out.
I will indeed be using XmlTextWriter but I meant to say whether to pass a physical file path string to the XmlTextWriter constructor (or, as John suggested, to the XmlTextWriter.Create() method) or use stream based api. My current code looks like the following:
XmlWriter objXmlWriter = XmlTextWriter.Create(new BufferedStream(new FileStream(#"C:\test.xml", FileMode.Create, System.Security.AccessControl.FileSystemRights.Write, FileShare.None, 1024, FileOptions.SequentialScan)), new XmlWriterSettings { Encoding = Encoding.Unicode, Indent = true, CloseOutput = true });
using (objXmlWriter)
{
//writing xml contents here
}
The rule of thumb is to use XmlWriter when the document need only be written and not worked with in memory, and to use XmlDocument (or the DOM) where you do need to work with it in memory.
Remember though, XmlWriter implements IDisposable, so do the following:
using (XmlWriter _XmlTextWriterObject = XmlWriter.Create(_xmlFilePath))
{
// Code to do the write here
}
While my code runs ok, my question is that is it the best approach?
As mentioned and your update, XmlWriter.Create is fine.
Or should I write the whole xml in memory stream first and then write the xml document in physical file from memory stream?
Do you have the memory to write the entire file in-memory? If you do then that approach will be faster, otherwise stream it using a FileStream which will take care of it for you.
And what are the effects on memory/ performance in both cases?
Reading the entire XML file in will use more memory, and spike the processor to start with. Streaming to disk will use more processor. But you'll need to be using a huge file for this to be noticeable given even desktop hardware now. If you're worried about the size increasing even more in the future, stick to the FileStream technique to future proof it.
As John Saunders mentioned it is better to use XmlWriter.Create(). That is the recommendation from the MSDN. The XmlWriter.Create() method can also take an XmlWriterSettings object. There you can customize your behavior quite a bit. If you don't need validation and character checking then you can turn it off and get a bit more speed. For example
XmlWriterSettings settings = new XmlWriterSettings();
settings.CheckCharacters = false;
using (XmlWriter writer = XmlWriter.Create("path", settings))
{
//writing code
writer.Flush();
}
Otherwise I think everything is okay.