I am trying to write some string to a file, and here is the code:
private static void WriteSelfDefinedFile(string msg)
{
ArrayList logTypes = SelfDefinedLogRule(msg);
// New some StreamWriter here
StreamWriter[] sws = new StreamWriter[selfDefinedLogFileName.Length];
for(int i = 0;i<selfDefinedLogFileName.Length;i++)
{
sws[i] = new StreamWriter(selfDefinedLogDir + selfDefinedLogFileName[i], true);
Debug.Log("111");
}
// It is writting here, not important for this question,I think.
foreach(SelfDefinedLogType temp in logTypes)
{
int index = (int)temp;
foreach (SelfDefinedLogType n in Enum.GetValues(typeof(SelfDefinedLogType)))
{
if(temp == n && sws[index]!=null)
{
sws[index].WriteLine(System.DateTime.Now.ToString() + ":\t"+ msg);
break;
}
else if(sws[index] == null)
{
LogError("File " + selfDefinedLogFileName[index] + " open fail");
}
}
}
// Close the StreamWrite[] here
for(int i=0;i<selfDefinedLogFileName.Length;i++)
{
sws[i].Close();
Debug.Log("222");
}
}
When the client is sending msg to server or server replying some msg to client, this funtion will be called to write some message to some files.
And unity throws the IOException:Sharing violation on path D:\SelfDefinedLogs\SentAndReceiveMsg.txt, sometimes. I mean, it doesn't happened everytime I write.
I have closed all the opened streamWriter at the end of the funtion, but the problem still come up.I am really confused.I will be grateful if anybody gives some solutions to this problem.
Related
I need to write and read data from serial port to my device. I've test certain approach where at first, I'm receiving the data using SerialDataReceivedEventArgs and I feel it is hard to read the port where I need to define the command that send where as the command is almost 200 commands.
My first approach is using:-
private void ObjCom_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (!ObjCom.IsOpen) return;
byte[] data = new byte[ObjCom.BytesToRead];
ObjCom.Read(data, 0, data.Length);
RaiseEventMsg("Buffer String: " + BitConverter.ToString(data).Replace("-", " "));
}
The RaiseEventMsg is a delegate event to pass current information to Main UI. The second approach is:-
private long lngTickCount = Convert.ToInt64(1000L);
public void StartWriteToPort()
{
byte[] Cmd = null;
string strCmd = string.Empty;
string strMsg = null;
bool bCont = true;
long lngCurrent = 0;
long lngNow = 0;
try
{
RaiseEventMsg("Start Write To Port");
ObjCom.DiscardOutBuffer();
ObjCom.DiscardInBuffer();
GetFullCommandByte(ref Cmd, Convert.ToByte(123)); // Referencing Cmd with return and pass Command List(various set of command)
ObjCom.Write(Cmd, 0, Cmd.Length);
strCmd = ByteArrayToString(Cmd); // Convert byte array to Hex string
RaiseEventMsg("Send: " + strCmd);
bool bTimeout = false;
lngCurrent = DateTime.Now.Ticks;
while (!bTimeout)
{
lngNow = DateTime.Now.Ticks;
if (lngNow > (lngCurrent + (3 * lngTickCount)))
{
bTimeout = true;
break;
}
}
lngCurrent = DateTime.Now.Ticks;
while (ObjCom.BytesToRead <= 0)
{
lngNow = DateTime.Now.Ticks;
if (lngNow > (lngCurrent + (1000 * lngTickCount)))
{
bCont = false;
break;
}
}
if (!bCont)
{
strMsg = "Error - Timeout Hit";
RaiseEventMsg(strMsg);
return;
}
int Idx = 0;
string strASCIIFull = string.Empty;
if ((ObjCom.BytesToRead > 0) & (bCont == true))
{
while (ObjCom.BytesToRead > 0)
{
var strASCII = ObjCom.ReadByte();
var TmpHex = System.Convert.ToString(strASCII, 16).ToUpper();
if (TmpHex.Length == 1)
{
strASCIIFull += (" 0" + TmpHex);
}
else
{
strASCIIFull += (" " + TmpHex);
}
lngCurrent = DateTime.Now.Ticks;
while (ObjCom.BytesToRead <= 0)
{
lngNow = DateTime.Now.Ticks;
if (lngNow > (lngCurrent + (2 * lngTickCount)))
{
bCont = false;
break;
}
}
Idx += 1;
}
}
RaiseEventMsg("Recv: " + strASCIIFull);
}
catch (System.Exception ex)
{
string error = $"Exception on StartWriteToPort. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
}
}
Problem on second approach is when I call this function for second time, the timeout will hit . But for Serial event, it does not have the problem, the protocol for timeout is set to 1 seconds. My device currently connected using USB without converter. The input cable to device is type B port (like standard printer port).
Is the any other way to read directly from port or any improvement on current code?
You need to learn how to layer your code. At the moment you have one long function that tries to do everything.
If you had several smaller functions that did specific things like reading or writing a chunk of information then it would make what you are trying to do simpler.
For example, serial communications generally have some sort of protocol that encapsulates how the packets of information are stored. Say the protocol was "", then you know every packet starts with an STX byte (0x01), a length byte, which tells you how many bytes are in the section, and there must be an ETX byte (0x02) at the end. You could write a function that would return an array of bytes that are just the because the function would interpret the stream and extract the relevant parts.
Then it might be as simple as:
var packet1 = ReadPacket();
WritePacket(outputData);
var packet2 = ReadPacket();
I have a very large file, almost 2GB in size. I am trying to write a process to read the file in and write it out without the first row. I pretty much have been only able to read and write one line at a time which takes forever. I can open it, remove the first row and save it faster in TextPad, though that is still very slow.
I use this code to get the number of records in the file:
private long getNumRows(string strFileName)
{
long lngNumRows = 0;
string strMsg;
try
{
lngNumRows = 0;
using (var strReader = File.OpenText(#strFileName))
{
while (strReader.ReadLine() != null)
{
lngNumRows++;
}
strReader.Close();
strReader.Dispose();
}
}
catch (Exception excExcept)
{
strMsg = "The File could not be read: ";
strMsg += excExcept.Message;
System.Windows.MessageBox.Show(strMsg);
//Console.WriteLine("Thee was an error reading the file: ");
//Console.WriteLine(excExcept.Message);
//Console.ReadLine();
}
return lngNumRows;
}
This only takes seconds to run. When I add the following code it takes forever to run. Am I doing something wrong? Why does the write add so much time? Any ideas on how I can make this faster?
private void ProcessTextFiles(string strFileName)
{
string strDataLine;
string strFullOutputFileName;
string strSubFileName;
int intPos;
long lngTotalRows = 0;
long lngCurrNumRows = 0;
long lngModNumber = 0;
double dblProgress = 0;
double dblProgressPct = 0;
string strPrgFileName = "";
string strOutName = "";
string strMsg;
long lngFileNumRows;
try
{
using (StreamReader srStreamRdr = new StreamReader(strFileName))
{
while ((strDataLine = srStreamRdr.ReadLine()) != null)
{
lngCurrNumRows++;
if (lngCurrNumRows > 1)
{
WriteDataRow(strDataLine, strFullOutputFileName);
}
}
srStreamRdr.Dispose();
}
}
catch (Exception excExcept)
{
strMsg = "The File could not be read: ";
strMsg += excExcept.Message;
System.Windows.MessageBox.Show(strMsg);
//Console.WriteLine("The File could not be read:");
//Console.WriteLine(excExcept.Message);
}
}
public void WriteDataRow(string strDataRow, string strFullFileName)
{
//using (StreamWriter file = new StreamWriter(#strFullFileName, true, Encoding.GetEncoding("iso-8859-1")))
using (StreamWriter file = new StreamWriter(#strFullFileName, true, System.Text.Encoding.UTF8))
{
file.WriteLine(strDataRow);
file.Close();
}
}
Not sure how much this will improve the performance, but surely, opening and closing the output file for every line that you want to write is not a good idea.
Instead open both files just one time and then write the line directly
using (StreamWriter file = new StreamWriter(#strFullFileName, true, System.Text.Encoding.UTF8))
using (StreamReader srStreamRdr = new StreamReader(strFileName))
{
while ((strDataLine = srStreamRdr.ReadLine()) != null)
{
lngCurrNumRows++;
if (lngCurrNumRows > 1)
file.WriteLine(strDataRow);
}
}
You could also remove the check on lngCurrNumRow simply making an empty read before entering the while loop
strDataLine = srStreamRdr.ReadLine();
if(strDataLine != null)
{
while ((strDataLine = srStreamRdr.ReadLine()) != null)
{
file.WriteLine(strDataRow);
}
}
Depending on the memory of your machine. You could try the following (my big file was "D:\savegrp.log" I had a 2gb file knocking about) This used about 6gb memory when I tried it
int counter = File.ReadAllLines(#"D:\savegrp.log").Length;
Console.WriteLine(counter);
It does depends on the memory available..
File.WriteAllLines(#"D:\savegrp2.log",File.ReadAllLines(#"D:\savegrp.log").Skip(1));
Console.WriteLine("file saved");
I am using this code to write to a text file:
int num;
StreamWriter writer2;
bool flag = true;
string str = "";
if (flag == File.Exists(this.location))
{
File.WriteAllText(this.location, string.Empty);
new FileInfo(this.location).Open(FileMode.Truncate).Close();
using (writer2 = this.SW = File.AppendText(this.location))
{
this.SW.WriteLine("Count=" + this.Count);
for (num = 0; num < this.Count; num++)
{
this.SW.WriteLine(this.Items[num]);
}
this.SW.Close();
}
}
but I keep Getting System.IOException saying that the process cannot access the file because it is being used by another process at this code:
File.WriteAllText(this.location, string.Empty);
However, I check the text file and I find that it was updated.
You should be able to replace all of your code with the following if Items is an enumerable of string.
if (File.Exists(this.location))
File.WriteAllLines(this.location, this.Items);
If it isn't and you are harnessing ToString() from each object in Items you can do this:
if (File.Exists(this.location))
{
var textLines = Items.Select(x => x.ToString());
File.WriteAllLines(this.location, textLines);
}
This should fix your issue with the file being locked because it is only accessing the file one time where your original code is opening it 3 times.
EDIT: Just noticed your addition of adding a "Count" line. Here's a cleaner version using a stream.
if (File.Exists(this.location))
{
using (var fileInfo = new FileInfo(this.location)
{
using(var writer = fileInfo.CreateText())
{
writer.WriteLine("Count=" + Items.Count);
foreach(var item in Items)
writer.WriteLine(item);
}
}
}
After importing plenty of XML files into application i tried to do modifications on it by using XML document class, for this i created few methods to do modifications.
The thing is the starting method it's working fine and when comes to the second one it's displaying System.IO exception like "File is already using another process".
So any one help me out how can i solve this issue.
Sample code what i'm doing:
Method1(fileList);
Method2(fileList);
Method3(fileList);
private void Method1(IList<RenamedImportedFileInfo> fileList)
{
try
{
string isDefaultAttribute = Resource.Resources.ImportIsDefaultAttribute;
string editorsPath = editorsFolderName + Path.DirectorySeparatorChar + meterType;
string profilesPath = profileFolderName + Path.DirectorySeparatorChar + meterType;
string strUriAttribute = Resource.Resources.ImportUriAttribute;
foreach (RenamedImportedFileInfo renameInfo in fileList)
{
if (renameInfo.NewFilePath.ToString().Contains(editorsPath) && (renameInfo.IsProfileRenamed != true))
{
var xmldoc = new XmlDocument();
xmldoc.Load(renameInfo.NewFilePath);
if (xmldoc.DocumentElement.HasAttribute(isDefaultAttribute))
{
xmldoc.DocumentElement.Attributes[isDefaultAttribute].Value = Resource.Resources.ImportFalse;
}
XmlNodeList profileNodes = xmldoc.DocumentElement.GetElementsByTagName(Resource.Resources.ImportMeasurementProfileElement);
if (profileNodes.Count == 0)
{
profileNodes = xmldoc.DocumentElement.GetElementsByTagName(Resource.Resources.ImportBsMeasurementProfileElement);
}
if (profileNodes.Count > 0)
{
foreach (RenamedImportedFileInfo profileName in oRenamedImportedFileList)
{
if (profileName.NewFilePath.ToString().Contains(profilesPath))
{
if (string.Compare(Path.GetFileName(profileName.OldFilePath), Convert.ToString(profileNodes[0].Attributes[strUriAttribute].Value, CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase) == 0)
{
profileNodes[0].Attributes[strUriAttribute].Value = Path.GetFileName(profileName.NewFilePath);
renameInfo.IsProfileRenamed = true;
break;
}
}
}
}
xmldoc.Save(renameInfo.NewFilePath);
xmldoc = null;
profileNodes = null;
}
}
oRenamedImportedFileList = null;
}
catch (NullReferenceException nullException) { LastErrorMessage = nullException.Message; }
}
Thanks,
Raj
You are probably opening the same file twice in your application. Before you can open it again, you have to close it (or leave it open and work on the same document without opening it again).
For help on how to implement this, please show us more code so we can give you advice.
Alright, The following code I've had in production for over a year with no changes. It has been working quite well. Within the past month more then a handful machines report that the xml documents are completely empty. They do not even contain a xml header . I cannot duplicate the files suddenly being empty, nor can i suggest a way for it to happen. I am hoping someone has had a similar issue that they solved.
Most of the machine that have been using this code have been using it for about a year, if not more. The empty files used to have data and lists in them.The files do not serialize at the same time. The save / serialize one after the other before the program exits.
My questions:
is it possible for the code below to create an empty file?
What else would cause them to be suddenly empty?
Has anyone else had issues with XML-serializer in the past month? (This problem has only happened in the past month on builds that have been stable for 3+ months.)
If you have questions or i missing something ask please. There also is a wide variety of types that i serialize... so if you can imagine it I probably have something similar that gets serialized.
public class BackEnd<T> {
public string FileSaveLocation = "this gets set on startup";
public bool DisabledSerial;
public virtual void BeforeDeserialize() { }
public virtual void BeforeSerialize() { }
public virtual void OnSuccessfulSerialize() { }
protected virtual void OnSuccessfulDeserialize(ListBackEnd<T> tmpList) { }
protected virtual void OnDeserialize(ListBackEnd<T> tmpList) { }
public virtual void serialize()
{
if (DisabledSerial)
return;
try
{
BeforeSerialize();
using (TextWriter textWrite = new StreamWriter(FileSaveLocation))
{
(new XmlSerializer(this.GetType())).Serialize(textWrite, this);
Debug.WriteLine(" [S]");
textWrite.Close();
}
OnSuccessfulSerialize();
}
catch (Exception e)
{
Static.Backup.XmlFile(FileSaveLocation);
Log.ErrorCatch(e,
"xml",
"serialize - " + typeof(T) + " - " + (new FileInfo(FileSaveLocation)).Name);
}
}
public virtual object deserialize(TextReader reader)
{
if (this.DisabledSerial)
return false;
ListBackEnd<T> tmp = null;
this.BeforeDeserialize();
if (reader == null && !File.Exists(this.FileSaveLocation))
{
Log.Write(Family.Error,
"xml",
"deserialize - " + this.GetType() + " - file not found. " + (new FileInfo(FileSaveLocation)).Name);
}
else
{
try
{
using (TextReader textRead = ((reader == null) ? new StreamReader(this.FileSaveLocation) : reader))
{
tmp = (ListBackEnd<T>)this.get_serializer().Deserialize(textRead);
Debug.WriteLine(" [D]");
textRead.Close();
}
OnSuccessfulDeserialize(tmp);
if (tmp != null)
{
this._Items = tmp._Items;
this.AutoIncrementSeed = tmp.AutoIncrementSeed;
if (this._Items.Count > this.AutoIncrementSeed && this._Items[0] is ItemStorage)
this.AutoIncrementSeed = this._Items.Max(item => (item as ItemStorage).Key);
}
}
catch (Exception e)
{
// this only copies the file
Static.Backup.XmlFile(FileSaveLocation);
// this only logs the exception
Log.ErrorCatch(e,
"xml",
"deserialize - " + typeof(T) + " - " + (new FileInfo(FileSaveLocation)).Name);
}
}
//{ Log.ErrorCatch(e, "xml", "deserialize" + this.GetType() + " - " + this.FileSaveLocation); }
OnDeserialize(tmp);
tmp = null;
return (_Items.Count > 0);
}
}
We've encountered this problem several times at $WORK, with the symptom being an empty file of the correct size but filled with zero bytes.
The solution we found was to set the WriteThrough value on the FileStream:
using (Stream file = new FileStream(settingTemp, FileMode.Create,
FileAccess.Write, FileShare.None,
0x1000, FileOptions.WriteThrough))
{
using (StreamWriter sw = new StreamWriter(file))
{
...
}
}
The only reason I can think that this would happen is that this line:
(new XmlSerializer(this.GetType())).Serialize(textWrite, this);
throws an exception and the textwriter is created and disposed without ever having anything written to it. I'd look at your log for errors.
What does
Static.Backup.XmlFile(FileSaveLocation);
do?