text append to existing file - c#

<namespace>
<root>
<node1>
<element 1>
<element 1>
</node1>
<node2>
<element 1>
<element 1>
</node2>
</root>
string stringContains = string.Empty;
foreach(string line in File.ReadLines(Path))
{
if(line.Contains("<Root>"))
{
stringContains = line.Replace("<Root>", "<Root>" + newelement.OuterXml);
}
}
File.AppendAllText(Path, stringContains);
I must replace root with other nodes,
so that i am appending text. However the above code appends existing text with stringContains

Try this.
string stringContains = string.Empty;
var lines = File.ReadLines(Path);
foreach (var line in lines)
{
if(line.Contains("<Root>"))
{
stringContains = line.Replace("<Root>", "<Root>" + newelement.OuterXml);
}
}
File.WriteAllLines(Path, lines);
but if your file size is huge then this is bad practise.

Note: You cannot change just one line in a file, you need to read all content, change desired part and write all content again.
According to your info about file size (GBs long) your only way to achive desired behaviour is to create new file and write content of you initial file changing only lines you need.
Procesing should be done line-by-line (as you showed in your sample) to achive minimum use of memory
However, this approach requieres 2X space on your HDD till operation is complete (assuming you will delete initial file after all is done)
Regarding details: this question provides complete sample of how to achive described approach

Related

Separating portions of XML file with text in C#

I need to write XML files with a tilde as a separator between portions, like so:
....
<Company>
<CompanyDetail>Blah</CompanyDetail>
<Phone>0000000000</Phone>
</Company>
~
<Company>
<CompanyDetail>Blah</CompanyDetail>
<Phone>0000000000</Phone>
</Company>
....
The way to do that normally in C# would be along the lines of
writer = new XmlTextWriter(fileName, Encoding.UTF8);
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
int remainingCompanies = companyList.Count;
foreach (Company company in companyList)
{
writer.WriteStartElement("Company");
writer.WriteStartElement("CompanyDetail");
writer.WriteString("company.companyDetail.toString()");
writer.WriteEndElement();
writer.WriteStartElement("Phone");
writer.WriteString("company.phone.toString()");
writer.WriteEndElement();
writer.WriteEndElement();
if (remainingCompanies-- > 1)
{
writer.WriteString(\n~\n);
}
}
But whenever I do this, the resulting XML file ends up being poorly formatted like so:
<Company>
<CompanyDetail>FirstCompany</CompanyDetail>
<Phone>1111111111</Phone>
</Company>
~
<Company><CompanyDetail>SecondCompany</CompanyDetail><Phone>2222222222</Phone></Company>
~
<Company><CompanyDetail>ThirdCompany</CompanyDetail><Phone>3333333333</Phone></Company>
....
When there's much more information for each company than just CompanyDetail and Phone, you can imagine how difficult it gets to look through the single line to visually find what you need in the XML.
My current workaround is to replace the tilde with a comment, but how do I have a tilde separating parts of this XML file AND maintain clean formatting?

How to get only xml from file in c#?

I have a problem with parsing file with XmlReader. I have a file containing info like this:
<Users>
<User>
<Email>email</Email>
<Key>23456</Key>
</User>
</Users>
asdfsof48f43uf489f3yf3y39fh3f489f3hf94[t]45.54tv,]5t
File contains xml values and then encrypted data from byte[] array.
The problem I've encountered is when i use:
using (var reader = XmlReader.Create(fileName))
{
while (reader.Read())
{
//parsing
}
}
I got 'System.Xml.XmlException' at line where encrypted bytes begin.
My question is: how to retrieve only xml part and only byte[] part?
If in case the encrypted data is always the last line you can use below snippet to read only XML part of data given that the XML data is limited in size
var fileLines = File.ReadAllLines(#"c:\temp\file.txt");
var xmlFromFile = string.Join("", fileLines, 0, fileLines.Length - 1);
using (var reader = XmlReader.Create(new StringReader(xmlFromFile)))
{
// Your logic goes here
}
you can do string parsing...
int start, end;
string myFile = File.ReadAllText("...");
start = myFile .IndexOf("<Users>");
end = myFile .IndexOf("</Users>") + 8;
myFile = myFile.Substring(start, end-start);
At that point you can load it into a xml document if you want. This all depends on you being 100% sure about the file format. This is a pretty fragile answer, so don't use it if you don't have a total trust in your input file.

Getting data from xml file and comparing it to a text file

So I have two files: a mot file and an xml file. What I need to do with these files is to read data from the xml file and compare it to the mot file if it exists. That's the general idea.
Before anything else, for those who are unfamiliar with what a mot
file is (I don't also have much knowledge about it, just the basics)...
(From Wikipedia) A mot file (or a Motorola S-Record
file) is a file format that conveys binary information in ASCII Hex text form.
(from another source) An S-record file consists of a
sequence of specially formatted ASCII character strings. An S-record
will be less than or equal to 78 bytes in length.
The format of a S-Record is:
S | Type | Record Length | Address (starting address) | Data | Checksum
(e.g. S21404200047524D5354524D0000801410AA5AA555F9)
([parsed] S2 14 042000 47524D5354524D0000801410AA5AA555 F9)
The specific idea is that I have data AA BB CC DD and so on allocated in addresses 0x042000 ~ 0x04200F. What’s written in the xml would be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data-set xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<record>
<File name="Test.mot">
<Address id="042000">
<Data>AA</Data>
</Address>
</File>
</record>
<record>
<File name="Test.mot">
<Address id="042001">
<Data>BB CC DD</Data>
</Address>
</File>
</record>
<record>
<File name="Test.mot">
<Address id="042004">
<Data>EE FF</Data>
</Address>
</File>
</record>
Then the program would get the data and address from he XML and search the .mot file for any hits. So if a mot file has a record S214042000AABBCCDDEEFF01234567891A2B3C4D5EF9, then this is supposed to bring a match with what's in the xml. Result to true, or 1. If anything in the xml doesn't have a match, then it would return with false or 0.
The problem now would be I’m not well-versed with C# much less with XML although I did have a tiny bit of experience with both. I initially thought it would be something like this:
using (StreamReader sr = new StreamReader("Test.mot"))
{
String line =String.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("042004") & line.Contains("EE FF"))
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine("Failure");
}
}
}
But obviously, it didn't result with what I expected. And Failure keeps popping up. Am I right to use StreamReader to read the .mot file? And with regards to the XML file, will XMLDocument work? How do I get data from the xml and compare it with the .mot file? Could someone walk me through how to get this done or provide guides how to properly start with this.
Let me know if I'm not clear on anything.
EDIT:
I thought of an idea. I'm not sure if it's doable, though. Let's say the program will read the mot S-Record file, and it will identify the type of the record. From there every record line listed in the file would be broken down as shown in the sample below:
sample record line: "S214042000AABBCCDDEEFF01234567891A2B3C4D5EF9"
S2 - type w/c means there would be a 3-byte address
14 - record length
F9 - checksum
042000 - AA
042001 - BB
042002 - CC
042003 - DD
...
04200F - 5E
With this new list, I think or I hope it would be easier for the program to use the data in the XML to locate it in the mot file.
Tell me if this will work, or if there are any alternatives.
Correct me when i'm wrong as it is full of assumptions:
the XML only gives the starting values of the data package under the mot file:
||||||||||||
S214042000AABBCCDDEEFF01234567891A2B3C4D5EF9
AABBCCDDEEFF
You could read out the xml and place each record in a record class
public class Record
{
string FileName{get;set;}
string Id {get;set;}
string Data {get;set;}
public Record(){} //default constructor
}
with the XmlDocument class you could read out the xml.
something like:
var document = new XmlDocument();
document.LoadXml("your.xml");
var records = document.SelectNodes("record");
var recordList = new List<Record>();
foreach(var r in records)
{
var file = r.SelectSingleNode("file");
var fileName = file.Attributes["name"].Value;
var address = file.SelectSingleNode("Address");
var id = address.Attributes["id"].Value;
var data = address.SelectSingleNode("Data").InnerText.Replace(" ", "");
recordList.Add(new Record{FileName = fileName, Id = id, Data = data});
}
Afterwards you can then readout everyline of the mot file by position:
since the location of the 042000 always be the 5 - 10 character
var fn = "Test.mot";
using (StreamReader sr = new StreamReader(fn))
{
var record = recordList.Single(r=> r.FileName);
String line =String.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.SubString(4,6) == record.Id && line.SubString(10, record.Data.Length) == record.Data)
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine("Failure");
}
}
}
Let me know if it helped you out a bit

How to monitor a text file and parse new lines?

I wondering if there is a way to monitor a .txt file without locking it and have the newly appended lines parsed in order to be sent to a database.
I know FileSystemWatcher will monitor the txt file without locking it and notify me if a change has occurred. The problem is that it does not tell the lines of data that has been appended. All of the examples I have looked at exclude the part of displaying newly appended lines or doing any processing of the new data. My program has the following structure:
static void Main(string[] args)
{
//string line;
//createWatcher (FileSystemWatcher)
foreach (string line in getLines(#"C://Documents/log.txt"))
{
string teststring = line;
string[] parts = line.Split(' ', ',', '-', '>', '[', ']');
StringBuilder builder = new StringBuilder();
foreach (string h in parts)
{
builder.Append(h).Append(" ");
}
string result = builder.ToString();
string cleanedString = System.Text.RegularExpressions.Regex.Replace(result, #"\s+", " ");
string trimString = cleanedString.Trim();
trimString = trimString.Remove(trimString.Length - 7);
//Console.WriteLine(trimString);
//Process new lines (parse/split)
//Connect and send to database
}
}
So my objective is to monitor a .txt file without locking it.
Read this file for existing data, and wait for appended data.
I then want to parse this data and send it to a database.
Does anyone know how to best approach this? or have a good tutorial?
Your best bet is for the code fired off of the file system watcher to keep track of the Position in the stream that's reading the file. Here's some pseudocode:
if(no stored position)
start at beginning of file
else
{
streamOfFile.Seek(storedPosition)
read until end of file
store stream.Postition
}
This could be done by tracking the length of the file the last time you read it, and then starting from that point next time. However, there are lots of race conditions around this since you're potentially reading from a file at the same time as the OS is writing.
Isn't your bigger problem that you can't guarantee that the only change to the file is an append? What happens if I insert a line at the top of the file, or replace the whole thing?

Reading the copied decimal value from excel

I am copying a value 8.03 from excel sheet and reading that value in C# from the clipboard using the code below. The value that is coming out is 8.0299999999999994 and not 8.03. When I look at the xml as in below the value is 8.0299999999999994. The sheet1.xml which is in the zip file of xlsx also has the value 8.02999999999999994. But when I copy the value to notepad the value gets copied at 8.03. What can I do to copy the value as 8.03 like in notepad?
DataObject retrievedData = Clipboard.GetDataObject() as DataObject;
if (retrievedData.GetDataPresent("XML Spreadsheet"))
{
var sourceDataReader = new XmlTextReader(retrievedData.GetData("XML Spreadsheet") as System.IO.Stream);
var doc = XDocument.Load(reader);
var excelWorksheeet = doc.Element("Worksheet");
XNamespace ns = "urn:schemas-microsoft-com:office:spreadsheet";
XName worksheetName = ns + "Worksheet";
var worksheetElement = doc.Root.Element(worksheetName);
}
The worksheetElement has the value:
<Worksheet ss:Name="Sheet1" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns="urn:schemas-microsoft-com:office:spreadsheet">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" ss:DefaultRowHeight="15">
<Row>
<Cell>
<Data ss:Type="Number">8.0299999999999994</Data>
</Cell>
</Row>
</Table>
</Worksheet>
The clipboard has support for several formats. Obviously the XML Spreadsheet format does a different rounding of the underlying float value than excel does. If you want to get the data exactly as notepad does, try to get the text representation instead.
Of course, copying as text will not get all the detailed information that XML Spreadsheet gives you, but it all depends on what you want to do with the data.
An alternative is to get both representations. Get the XML Spreadsheet format to get the detailed data and use the text format to get a display string.

Categories