Can't create a file when users generate at a same time - c#

I have a code to create an xml file on a server directory,
this code is working like a charm until users process this code at A SAME TIME.
the user who has a milliseconds faster will success generate a file and the other will losing it.
please help me guys.
public static void XmlOrder(arg_order mod, string NewAddress)
{
XmlDocument XDoc = new XmlDocument();
XmlDeclaration xde = XDoc.CreateXmlDeclaration("1.0", "", "");
XDoc.AppendChild(xde);
XmlElement XElemRoot = XDoc.CreateElement("Digital_Order");
XElemRoot.SetAttribute("xmlns", "");
XDoc.AppendChild(XElemRoot);
foreach (arg_order modDetail in mod.arg_orders) {
XmlElement Xsource = XDoc.CreateElement("Document");
XElemRoot.AppendChild(Xsource);
XmlElement XTemp = XDoc.CreateElement("wt_web_Id");
XTemp.InnerText = modDetail.order_detail_id.ToString();
Xsource.AppendChild(XTemp);
XTemp = XDoc.CreateElement("wt_addr");
XTemp.InnerText = modCompany.qad_no;
Xsource.AppendChild(XTemp);
}
//naming and path
string name = arg_order_detail.FindAll().Count.ToString() + ".xml";
string path = ArgenXmlOrderPath + "/" + name;
XDoc.Save(path);
}

That is cause your users are trying to write the same file at the same time.
Make your file names unique by adding something like the orderID to the name of the file.
string name = modDetail.order_detail_id.ToString() + ".xml";
string path = ArgenXmlOrderPath + "/" + name;
XDoc.Save(path);

Related

Problem with creating file on mobile device with function in game script. Access to the path is denied

I made game where all of player stats are storage in XML file. When I build a game at mobile device I get an error:
readonly string datapath = #"data.xml";
void CreateNewXMLFile(string name)
{
XmlDocument gamedata = new XmlDocument();
XmlNode docNode = gamedata.CreateXmlDeclaration("1.0", "UTF-8", null);
gamedata.AppendChild(docNode);
//Username
XmlNode GameUsersNode = gamedata.CreateElement("GameUser");
gamedata.AppendChild(GameUsersNode);
//User
XmlNode Username = gamedata.CreateElement("Username");
Username.InnerText = name;
GameUsersNode.AppendChild(Username);
//Lastlogged
XmlNode LastloggedTime = gamedata.CreateElement("LastloggedTime");
LastloggedTime.InnerText = System.DateTime.Now.ToString();
GameUsersNode.AppendChild(LastloggedTime);
//Stage
XmlNode Stage = gamedata.CreateElement("Stage");
Stage.InnerText = "1";
GameUsersNode.AppendChild(Stage);
//Money
XmlNode Money = gamedata.CreateElement("Money");
Money.InnerText = "0";
GameUsersNode.AppendChild(Money);
//GreenHeroLvl
XmlNode GreenHeroLvl = gamedata.CreateElement("GreenHeroLvl");
GreenHeroLvl.InnerText = "0";
GameUsersNode.AppendChild(GreenHeroLvl);
//BlackHero
XmlNode BlackHero = gamedata.CreateElement("BlackHero");
BlackHero.InnerText = "0";
GameUsersNode.AppendChild(BlackHero);
//AssasinHero
XmlNode AssasinHero = gamedata.CreateElement("AssasinHero");
AssasinHero.InnerText = "0";
GameUsersNode.AppendChild(AssasinHero);
gamedata.Save(datapath);
}
Error is:
06-24 21:04:47.092: E/Unity(22918): UnauthorizedAccessException: Access to the path "/data.xml" is denied.
You are trying to write to a system path /data.xml.
On Android you usually don't have permissions to write anything to the root / folder!
I guess you rather want to write e.g. to the Application.persistentDataPath folder like
readonly string datapath = Path.Combine(Application.persistentDataPath, "data.xml");
which on Android results in a valid path like
/storage/emulated/0/Android/data/<packagename>/files/data.xml

Split XML file in C#

I have an XML file which have multiple messages in one large file, my objective it to split the file into singe xml file for each message, I have a c# code which only gets me the first instance of the message. can you please tell what am I missing here:
Here is my code :
string strSeq;
string strFileName;
XDocument doc = XDocument.Load(#"C:\XMl\MR.xml");
var newDocs = doc.Descendants("Message")
.Select(d => new XDocument(new XElement("FileDump", d)));
foreach (var newDoc in newDocs)
{
strSeq = XDocument.Load(#"C:\XMl\MR.xml").XPathSelectElement
"//FileDump/Message/MsgID").Value;
strFileName = "MR_" + strSeq + ".xml";
newDoc.Save(Console.Out); Console.WriteLine();
newDoc.Save(#"C:\xml\MR\Tst\" + strFileName);
Console.WriteLine();
}
You should search for message ID within newDoc instead of doc:
foreach (var newDoc in newDocs)
{
strSeq = newDoc.XPathSelectElement("//FileDump/Message/MsgID").Value;
strFileName = "MR_" + strSeq + ".xml";
newDoc.Save(Console.Out); Console.WriteLine();
newDoc.Save(#"C:\xml\MR\Tst\" + strFileName);
Console.WriteLine();
}
Try,
string path = #"C:\xml\MR\Tst\MR_";
XElement root = XElement.Load(file);
foreach(XElement message in root.Descendants("Message"))
{
string id = message.Element("MsgID").Value;
message.Save(path + id + ".xml");
}

Inserting data at specific position in XML

I want to read an XML file and match tag </contrib-group> and write a string after this tag
string Final = File.ReadAllText(Npath);
string Oxml = path + "\\" + Oword + ".abs.xml";
if (File.Exists(Oxml))
{
StreamReader xml = new StreamReader(Oxml,Encoding.UTF8);
string xmltag = xml.ReadToEnd();
//File.OpenWrite(Oxml);
xml.Close();
StreamWriter write = new StreamWriter(Oxml, true, Encoding.UTF8);
Match tag = Regex.Match(xmltag, #"</contrib-group>");
if (tag.Success == true)
{
write.WriteLine(Environment.NewLine);
write.Write(Final);
}
}
So I need to write the string Final to the XML file called Oxml after the matched XML tag </contrib-group>
If you are willing to save the new content as a valid XML file which you can work with, you should use the XML classes for that approach, this should look like this (untested):
XmlDocument doc = new XmlDocument();
doc.Load("YourFile.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList elemList = root.GetElementsByTagName("contrib-group");
for (int i=0; i < elemList.Count; i++)
{
XmlNode xnode = elemList[i];
XmlNode xnodeParent = xnode.ParentNode;
XMLNode newNode = doc.CreateNode(XmlNodeType.Element, "NodeName", "");
newNode.InnerText = "ContentInsideTheNode";
xnodeParent.InsertAfter(newNode, xnode);
}
doc.Save("YourFile.xml");
If you only need to replace the string for other purposes than saving it where having a valid XML is not an issue you can just handle it as a string and use the String.Replace (String, String) Method
string searchedTag = #"</contrib-group>";
string tagAndNewContent = #"</contrib-group>" + newContent;
string fileContentString = File.ReadAllText("YourFile.xml");
string ouput = fileContentString.Replace(searchedTag, tagAndNewContent);

Reading specific text from XML files

I have created a small XML tool which gives me count of specific XML tags from multiple XML files.
The code for this is as follow:
public void SearchMultipleTags()
{
if (txtSearchTag.Text != "")
{
try
{
//string str = null;
//XmlNodeList nodelist;
string folderPath = textBox2.Text;
DirectoryInfo di = new DirectoryInfo(folderPath);
FileInfo[] rgFiles = di.GetFiles("*.xml");
foreach (FileInfo fi in rgFiles)
{
int i = 0;
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(fi.FullName);
//rtbox2.Text = fi.FullName.ToString();
foreach (XmlNode node in xmldoc.GetElementsByTagName(txtSearchTag.Text))
{
i = i + 1;
//
}
if (i > 0)
{
rtbox2.Text += DateTime.Now + "\n" + fi.FullName + " \nInstance: " + i.ToString() + "\n\n";
}
else
{
//MessageBox.Show("No Markup Found.");
}
//rtbox2.Text += fi.FullName + "instances: " + str.ToString();
}
}
catch (Exception)
{
MessageBox.Show("Invalid Path or Empty File name field.");
}
}
else
{
MessageBox.Show("Dont leave field blanks.");
}
}
This code returns me the tag counts in Multiple XML files which user wants.
Now the same I want to Search for particular text and its count present in XML files.
Can you suggest the code using XML classes.
Thanks and Regards,
Mayur Alaspure
Use LINQ2XML instead..It's simple and a complete replacement to othe XML API's
XElement doc = XElement.Load(fi.FullName);
//count of specific XML tags
int XmlTagCount=doc.Descendants().Elements(txtSearchTag.Text).Count();
//count particular text
int particularTextCount=doc.Descendants().Elements().Where(x=>x.Value=="text2search").Count();
System.Xml.XPath.
Xpath supports counting: count(//nodeName)
If you want to count nodes with specific text, try count(//*[text()='Hello'])
See How to get count number of SelectedNode with XPath in C#?
By the way, your function should probably look something more like this:
private int SearchMultipleTags(string searchTerm, string folderPath) { ...
//...
return i;
}
Try using XPath:
//var document = new XmlDocument();
int count = 0;
var nodes = document.SelectNodes(String.Format(#"//*[text()='{0}']", searchTxt));
if (nodes != null)
count = nodes.Count;

c# service renaming files!

I have a windows service , that takes files with metadata(FIDEF) and corresponding video file and , translates the XML(FIDEF) using XSLT .
I get the file directory listing for FIDEF's and if a video file of the same name exists it translates it. That works ok , but it is on a timer to search every minute. I am trying to handle situations where the same file name enters the input directory but is already in the output directory. I just have it changing the output name to (copy) thus if another file enters i should get (copy)(copy).mov but the service won't start with filenames of the same directory already in the output , it works once and then does not seem to pick up any new files.
Any Help would be great as I have tried a few things with no good results. I believe its the renaming methods, but I've put most of the code up in case its a clean up issue or something else.
(forgive some of the names just trying different things).
private void getFileList()
{
//Get FILE LIST FROM Directory
try
{
// Process Each String/File In Directory
string result;
//string filename;
filepaths = null;
filepaths = Directory.GetFiles(path, Filetype);
foreach (string s in filepaths)
{
for (int i = 0; i < filepaths.Length; i++)
{
//Result Returns Video Name
result = Path.GetFileNameWithoutExtension(filepaths[i]);
FileInfo f = new FileInfo(filepaths[i]);
PreformTranslation(f, outputPath + result , result);
}
}
}
catch (Exception e)
{
EventLog.WriteEntry("Error " + e);
}
}
private void MoveVideoFiles(String Input, String Output)
{
File.Move(Input, Output);
}
private string GetUniqueName(string name)
{
//Original Filename
String ValidName = name;
//remove FIDEF from filename
String Justname1 = Path.GetFileNameWithoutExtension(name);
//get .mov extension
String Extension2 = Path.GetExtension(Justname1);
//get filename with NO extensions
String Justname = Path.GetFileNameWithoutExtension(Justname1);
//get .Fidef
String Extension = Path.GetExtension(name);
int cnt = 0;
//string[] FileName = Justname.Split('(');
//string Name = FileName[0];
while (File.Exists(ValidName)==true)
{
ValidName = outputPath + Justname + "(Copy)" + Extension2 + Extension;
cnt++;
}
return ValidName;
}
private string getMovFile(string name)
{
String ValidName = name;
String Ext = Path.GetExtension(name);
String JustName = Path.GetFileNameWithoutExtension(name);
while(File.Exists(ValidName))
{
ValidName = outputPath + JustName + "(Copy)" + Ext;
}
return ValidName;
}
//Preforms the translation requires XSL & FIDEF name.
private void PreformTranslation(FileInfo FileName, String OutputFileName , String result)
{
string FidefName = OutputFileName + ".FIDEF";
String CopyName;
String copyVidName = outputPath + result;
XslCompiledTransform myXslTransform;
myXslTransform = new XslCompiledTransform();
try
{
myXslTransform.Load(XSLname);
}
catch
{
EventLog.WriteEntry("Error in loading XSL");
}
try
{ //only process FIDEF's with corresponding Video file
if (AllFidef == "no")
{
//Check if video exists if yes,
if (File.Exists(path + result))
{
//Check for FIDEF File Already Existing in the Output Directory.
if (File.Exists(FidefName))
{
//Get unique name
CopyName = GetUniqueName(FidefName);
copyVidName= getMovFile(copyVidName);
//Translate and create new FIDEF.
//double checking the file is here
if (File.Exists(outputPath + result))
{
myXslTransform.Transform(FileName.ToString(), CopyName);
File.Delete(FileName.ToString());
MoveVideoFiles(path + result, copyVidName);
}
////Move Video file with Corresponding Name.
}
else
{ //If no duplicate file exsists in Directory just move.
myXslTransform.Transform(FileName.ToString(), OutputFileName + ".FIDEF");
MoveVideoFiles(path + result, outputPath + result);
}
}
}
else
{
//Must have FIDEF extension
//Processes All FIDEFS and moves any video files if found.
myXslTransform.Transform(FileName.ToString(), OutputFileName + ".FIDEF");
if (File.Exists(path + result))
{
MoveVideoFiles(path + result, outputPath + result);
}
}
}
catch (Exception e)
{
EventLog.WriteEntry("Error Transforming " + "FILENAME = " + FileName.ToString()
+ " OUTPUT_FILENAME = " + OutputFileName + "\r\n" +"\r\n"+ e);
}
}
There is a lot wrong with your code. getFileList has the unneeded inner for loop for starters. Get rid of it. Your foreach loop has s, which can replace filepaths[i] from your for loop. Also, don't do outputPath + result to make file paths. Use Path.Combine(outputPath, result) instead, since Path.Combine handles directory characters for you. Also, you need to come up with a better name for getFileList, since that is not what the method does at all. Do not make your method names liars.
I would simply get rid of MoveVideoFiles. The compiler just might too.
GetUniqueName only works if your file name is of the form name.mov.fidef, which I'm assuming it is. You really need better variable names though, otherwise it will be a maintenance nightware later on. I would get rid of the == true in the while loop condition, but that is optional. The assignment inside the while is why your files get overwritten. You always generate the same name (something(Copy).mov.fidef), and as far as I can see, if the file exists, I think you blow the stack looping forever. You need to fix that loop to generate a new name (and don't forget Path.Combine). Maybe something like this (note this is untested):
int copyCount = 0;
while (File.Exists(ValidName))
{
const string CopyName = "(Copy)";
string copyString = copyCount == 0 ? CopyName : (CopyName + "(" + copyCount + ")");
string tempName = Justname + copyString + Extension2 + Extension;
ValidName = Path.Combine(outputPath, tempName);
copyCount++;
}
This generates something(Copy).mov.fidef for the first copy, something(Copy)(2).mov.fidef for the second, and so on. Maybe not what you want, but you can make adjustments.
At this point you have a lot to do. getMovFile looks as though it could use work in the same manner as GetUniqueName. You'll figure it out. Good luck.

Categories