I've created a program that read and write values from an XML file. When I try to save the XML with xmlDoc.Save(path); it throws an exception because the file is already used by another process.
Read Method:
private void ReadXml()
{
//instantiate the xmlDocument
xmlDoc = new XmlDocument();
//declare an XmlNodeList
XmlNodeList xmlNode;
//create a FileStream to read the file
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
//load the file
xmlDoc.Load(fs);
//get all the nodes from the file
xmlNode = xmlDoc.GetElementsByTagName("Drop");
//read all values frome the nodes and save it into variables
for (int i = 0; i <= xmlNode.Count - 1; i++)
{
string name= xmlNode[i].ChildNodes.Item(0).InnerText.Trim();
int DefaultMin= Convert.ToInt32(xmlNode[i].ChildNodes.Item(1).InnerText.Trim());
int DefaultMax = Convert.ToInt32(xmlNode[i].ChildNodes.Item(2).InnerText.Trim());
int min = Convert.ToInt32(xmlNode[i].ChildNodes.Item(3).InnerText.Trim());
int max= Convert.ToInt32(xmlNode[i].ChildNodes.Item(4).InnerText.Trim());
int line= Convert.ToInt32(xmlNode[i].ChildNodes.Item(5).InnerText.Trim());
string lineToChange = xmlNode[i].ChildNodes.Item(6).InnerText;
string filePath = xmlNode[i].ChildNodes.Item(7).InnerText.Trim();
//create the DropItem object
DropItem drop = new DropItem(name, DefaultMin, DefaultMax, line, lineToChange, installPath+filePath);
drop.MinValue = min;
drop.MaxValue = max;
//add the object to the list
drops.Add(drop);
}
}
Write Method:
public void WriteXml()
{
//declare a xmlNodeList
XmlNodeList xmlNode;
//create a FileStream to read the file
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
//load the file
xmlDoc.Load(fs);
//get all the nodes from the file
xmlNode = xmlDoc.GetElementsByTagName("Drop");
//write the values in the xml
for (int i = 0; i <= drops.Count - 1; i++)
{
xmlNode[i].ChildNodes.Item(3).InnerText=drops[i].MinValue.ToString();
xmlNode[i].ChildNodes.Item(4).InnerText = drops[i].MaxValue.ToString();
}
//save the document
xmlDoc.Save(path);
}
I think I have to close the xmlDoc in the read method before saving it.
You are not closing the stream,
use Using statement in order to dispose and close the FileStream :
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
//load the file
xmlDoc.Load(fs);
//get all the nodes from the file
xmlNode = xmlDoc.GetElementsByTagName("Drop");
}
Try adding using to the File Stream this should help guarantee that the file from the File Stream is not in use.
public void WriteXml()
{
//declare a xmlNodeList
XmlNodeList xmlNode;
//create a FileStream to read the file
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
//load the file
xmlDoc.Load(fs);
//get all the nodes from the file
xmlNode = xmlDoc.GetElementsByTagName("Drop");
//write the values in the xml
for (int i = 0; i <= drops.Count - 1; i++)
{
xmlNode[i].ChildNodes.Item(3).InnerText=drops[i].MinValue.ToString();
xmlNode[i].ChildNodes.Item(4).InnerText = drops[i].MaxValue.ToString();
}
}
//save the document
xmlDoc.Save(path);
}
Try to Dispose the FileStream object at the end of ReadXml and WriteXml methods.
Related
I'm reading a binary file and writing to another file in CP 437 format by skipping few lines. But the output file size is increased than the original file and also data is corrupted. Any help to identify the issue.
StreamReader sStreamReader = new StreamReader(#"D:\Denesh\Input.txt");
string AllData = sStreamReader.ReadToEnd();
string[] rows = AllData.Split(",".ToCharArray());
FileStream fileStream = new FileStream(TransLog, FileMode.Open);
StreamReader streamReader = new StreamReader((Stream)fileStream, Encoding.GetEncoding(437));
StreamWriter streamWriter = new StreamWriter(outFile, false);
int num = 0;
int count = 0;
while (!streamReader.EndOfStream)
{
string tlogline = streamReader.ReadLine();
if (rows[count] == Convert.ToString(num))
{
++count;
}
else
{
++num;
streamWriter.WriteLine(tlogline, streamReader.CurrentEncoding);
}
}
fileStream.Close();
streamWriter.Close();
Adding filestream for streamwriter solves the issue. Thanks.
I want to read a binary file line by line (I'm writing of course continously, but I know that after 457 bytes new data start and I know exactly the byte structure and where which information is written to) and change a special entry of the line. I get an System.IO.IOException when I try to access the same file with both BinaryReader and BinaryWriter. I use locking to prevent that the file is accessed from somewhere else.
My code is:
using (FileStream fs2 = new FileStream(testfile, FileMode.Open, FileAccess.Read))
{
using (BinaryReader r = new BinaryReader(fs2))
{
using (BinaryWriter bw = new BinaryWriter(new FileStream(testfile, FileMode.Open, FileAccess.Write), utf8))
{
for (int i = 0; i < 11000; i+=457)
{
int myint = r.ReadInt64();
bw.Seek(i, SeekOrigin.Current);
bw.Write(myint*2);
}
}
}
}
How can I do this?
Do not create the second FileStream because the file is locked for the read operation by the first FileStream object.
If you are sure about file structure, the exception only can come out from 2nd FileStream instantiation. See link below for more information:
Read and Write to File at the same time
It is working for me using the following code:
if (File.Exists(testfile))
{
FileInfo fi = new FileInfo(testfile);
using (FileStream fs2 = new FileStream(testfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (BinaryReader r = new BinaryReader(fs2))
{
r.BaseStream.Seek(0, SeekOrigin.Begin);
using (BinaryWriter bw = new BinaryWriter(new FileStream(testfile, FileMode.Open, FileAccess.Write, FileShare.ReadWrite)))
{
for (int i = 0; i <= (fi.Length-177); i += 177)//181
{
}
}
}
}
}
I'm trying to copy the contents of one Excel file to another Excel file while replacing a string inside of the file on the copy. It's working for the most part, but the file is losing 27 kb of data. Any suggestions?
public void ReplaceString(string what, string with, string path) {
List < string > doneContents = new List < string > ();
List < string > doneNames = new List < string > ();
using(ZipArchive archive = ZipFile.Open(_path, ZipArchiveMode.Read)) {
int count = archive.Entries.Count;
for (int i = 0; i < count; i++) {
ZipArchiveEntry entry = archive.Entries[i];
using(var entryStream = entry.Open())
using(StreamReader reader = new StreamReader(entryStream)) {
string txt = reader.ReadToEnd();
if (txt.Contains(what)) {
txt = txt.Replace(what, with);
}
doneContents.Add(txt);
string name = entry.FullName;
doneNames.Add(name);
}
}
}
using(MemoryStream zipStream = new MemoryStream()) {
using(ZipArchive newArchive = new ZipArchive(zipStream, ZipArchiveMode.Create, true, Encoding.UTF8)) {
for (int i = 0; i < doneContents.Count; i++) {
int spot = i;
ZipArchiveEntry entry = newArchive.CreateEntry(doneNames[spot]);
using(var entryStream = entry.Open())
using(var sw = new StreamWriter(entryStream)) {
sw.Write(doneContents[spot]);
}
}
}
using(var fileStream = new FileStream(path, FileMode.Create)) {
zipStream.Seek(0, SeekOrigin.Begin);
zipStream.CopyTo(fileStream);
}
}
}
I've used Microsoft's DocumentFormat.OpenXML and Excel Interop, however, they are both lacking in a few main components that I need.
Update:
using(var fileStream = new FileStream(path, FileMode.Create)) {
var wrapper = new StreamWriter(fileStream);
wrapper.AutoFlush = true;
zipStream.Seek(0, SeekOrigin.Begin);
zipStream.CopyTo(wrapper.BaseStream);
wrapper.Flush();
wrapper.Close();
}
Try the process without changing the string and see if the file size is the same. If so then it would seem that your copy is working correctly, however as Marc B suggested, with compression, even a small change can result in a larger change in the overall size.
How do I load an XML document in read-only mode?
I have an XML file which is opened in another process and I want to load it in my C# application as read-only.
XmlDocument.Load("file.xml") obviously throws this error:
Process cannot access a file because it is being used by another
process
So I tried stream reader too:
FileStream fs = new FileStream("file.xml", FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
But it also throws the same error.
So how can I access my XML Document in read-only mode?
Update
I tried XPathDocument and FileStream("file.xml", FileMode.Open, FileAccess.Read,FileShare.Read) as well. But neither of them solved the problem.
This class Shows read xml file in read only mode.
public List<string[]> GetRunningOrderOnTable(string tableNo, int shopid)
{
try
{
XmlDocument xmlDoc = new XmlDocument();
string xmlFilePath = #"C:\inetpub\wwwroot\ShopAPI\XmlData\RunningTables.xml";
//string xmlFilePath = HttpContext.Current.Server.MapPath("~/XmlData/RunningTables.xml");
// Option 1
// FileStream xmlFile = new FileStream(xmlFilePath, FileMode.Open,
//FileAccess.Read, FileShare.Read);
// xmlDoc.Load(xmlFile);
// Option 2
using (Stream s = File.OpenRead(xmlFilePath))
{
xmlDoc.Load(s);
}
//xmlDoc.Load(xmlFilePath);
List<string[]> st = new List<string[]>();
XmlNodeList userNodes = xmlDoc.SelectNodes("//Tables/Table");
if (userNodes != null)
{
foreach (XmlNode userNode in userNodes)
{
string tblNo = userNode.Attributes["No"].Value;
string sid = userNode.Attributes["ShopID"].Value;
if (tblNo == tableNo && sid == shopid.ToString())
{
string[] str = new string[5];
str[0] = userNode.Attributes["No"].Value;
str[1] = userNode.InnerText; // OrderNumber
str[2] = userNode.Attributes["OrderID"].Value;
str[3] = userNode.Attributes["OrderedOn"].Value;
str[4] = userNode.Attributes["TotalAmount"].Value;
st.Add(str);
}
}
}
else return new List<string[]>();
return st;
}
catch (Exception ex)
{
CustomLogging.Log("RunningTables.xml GetRunningOrderOnTable Error " + ex.StackTrace, LoggingType.XMLRead);
return new List<string[]>();
}
}
Given you've said that FileShare.Read doesn't work, it would appear that the other process has the file open for writing.
You could try opening it with FileAccess.Read and FileShare.ReadWrite, in which case you'll need to handle any errors that may occur if the other process does actually write to the file.
If that doesn't work, it's likely that the other process has it opened with FileShare.None, in which case there's nothing you can do about it. To check this, try opening the file with, say, Notepad.
But is it still possible for FileShare.ReadWrite to throws error if it works in most cases?
You will only get an error if another process has already opened the file using FileShare.None. You've confirmed that this isn't the case when it's open in Microsoft Word, so you should be OK.
In Linux, a lot of IPC is done by appending to a file in 1 process and reading the new content from another process.
I want to do the above in Windows/.NET (Too messy to use normal IPC such as pipes). I'm appending to a file from a Python process, and I want to read the changes and ONLY the changes each time FileSystemWatcher reports an event. I do not want to read the entire file content into memory each time I'm looking for changes (the file will be huge)
Each append operation appends a row of data that starts with a unique incrementing counter (timestamp+key) and ends with a newline.
using (FileStream fs = new FileStream
(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (someCondition)
{
while (!sr.EndOfStream)
ProcessLinr(sr.ReadLine());
while (sr.EndOfStream)
Thread.Sleep(100);
ProcessLinr(sr.ReadLine());
}
}
}
this will help you read only appended lines
You can store the offset of the last read operation and seek the file to that offset when you get a changed file notification. An example follows:
Main method:
public static void Main(string[] args)
{
File.WriteAllLines("test.txt", new string[] { });
new Thread(() => ReadFromFile()).Start();
WriteToFile();
}
Read from file method:
private static void ReadFromFile()
{
long offset = 0;
FileSystemWatcher fsw = new FileSystemWatcher
{
Path = Environment.CurrentDirectory,
Filter = "test.txt"
};
FileStream file = File.Open(
"test.txt",
FileMode.Open,
FileAccess.Read,
FileShare.Write);
StreamReader reader = new StreamReader(file);
while (true)
{
fsw.WaitForChanged(WatcherChangeTypes.Changed);
file.Seek(offset, SeekOrigin.Begin);
if (!reader.EndOfStream)
{
do
{
Console.WriteLine(reader.ReadLine());
} while (!reader.EndOfStream);
offset = file.Position;
}
}
}
Write to file method:
private static void WriteToFile()
{
for (int i = 0; i < 100; i++)
{
FileStream writeFile = File.Open(
"test.txt",
FileMode.Append,
FileAccess.Write,
FileShare.Read);
using (FileStream file = writeFile)
{
using (StreamWriter sw = new StreamWriter(file))
{
sw.WriteLine(i);
Thread.Sleep(100);
}
}
}
}