So from what I understand of a string vs StringBuilder is that string builder will actually modify the instance of itself while string will just make a new one. So if I understand this correctly then by using the string method for a constantly changing variable I could basically be eventually using all the memory until the computer needs to dump it to make room.
What I am doing is using an event handler to monitor serial communication. I will take in the data and parse it out plus display it in a text box. The event handler uses string to accomplish this currently. In concern for better programming and not using up all the memory when I don't need to I am trying to clean up my code.
I started to code with string builder and begun to get the build error that StringBuilder does not contain a .contains method.
Basically I am curious if i should leave it alone? Should I approach this differently? and do I have the right understanding in that string will inevitably run me out of memory?
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
rx.AppendText(Environment.NewLine + indata);
string dataCheck = indata.ToUpper();
if (dataCheck.Contains("CONNECT") || indata.Contains("CONNECTED"))
{
cState.Text = "Connected";
connectLink();
}
if (dataCheck.Contains("NO CARRIER"))
{
cState.Text = "Disconnected";
disconnect();
}
dataCheck = null;
}
You are incorrect; using String will not (in general) cause you to run out of memory.
If you're doing lots of concatenation, using string is less efficient, since it needs to build a new string and throw away the old string every time you concatenate.
In such scenarios, you should use a StringBuilder to build the string, then call ToString() whenever you want to display it.
Your code does not contain any concatenation, so using StringBuilder wouldn't do any good.
Related
I have one TELNET SERVER here, and this USSR Vessel v1.0 program is the client, it will be connected to the telnet server, the telnet server SPAMS, I mean sends the data very fast to the client .
(Well, originally the telnet server is a microcontroller that reads 5 sensors and the data will be sent back to the client so this should be quite slower than the C# program telnet server I use as a substitute)
The problem is this, I use regex to split the string coming from the server.
The string should be like this: Q0.00W0.10X0.30Y0.44Z99.00, you see, I'm erasing the Q/W/X/Y/Z and then store the values in a string array and then print them out into 5 labels, but I'm getting this error, see the screenshot below. I added a large textbox for debugging purposes. See my code in receiving the string via telnet:
public void OnAddMessage(string sMessage)
{
//Q0.00W0.10X0.30Y0.44Z99.00
string[] lines = Regex.Split(sMessage, "\r\n");
foreach (string line in lines)
{
Console.WriteLine(line);
valuesStr[ctr2] = line;
ctr2++;
}
ctr2 = 0;
m_lbRecievedData.Items.Add(sMessage);
tempVal.Text = valuesStr[4]+ "°C";
frontVal.Text = valuesStr[0];
backVal.Text = valuesStr[1];
leftVal.Text = valuesStr[2];
rightVal.Text = valuesStr[3];
}
Your question needs more clarification of what you want. As it stands, the code does nothing to accomplish what you claim it to be doing, namely "erasing the Q/W/X/Y/Z and then store the values in a string array".
Nevertheless, here's an attempt at addressing the problem phrased in the question:
using System.Text.RegularExpressions;
private Regex regex = new Regex("[QWXYZ]");
private void OnAddMessage(string message)
{
using (StringReader sr = new StringReader(message))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] splitContents = regex.Split(line);
//do something with the parsed contents ...
}
}
}
Try the RegEx implementation from the Micro Framework
http://netmf.codeplex.com/
Here is a web cast explaining it!
http://channel9.msdn.com/coding4fun/blog/Net-Micro-Framework-v42-RTWs
It's arguably better because it allows you to match for an explicit amount of time and then resume where you left off.. something which is not easily possible by default with the Full Fx.
http://www.codeproject.com/Articles/386890/String-Manipulation-in-the-NET-Micro-Framework
I have no doubt that this questions are of very basic character but for me it's quite hard...
I want to select a filename/path with saveFileDialog.
Like this:
private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{
// Get file name.
string name = saveFileDialog1.FileName;
Source: http://www.dotnetperls.com/savefiledialog
Then I want to declare StreamWriter with the Path from above (suppose this works like this)
System.IO.StreamWriter file = new System.IO.StreamWriter(saveFileDialog1_FileOk.FileName);
This had to be done in the saveFileDialog1_FileOk function. Then I want to write to that file from another function/event handler (SerialPort has received data). And the filename should be able to change to a new file while runtime so that the data from the eventhandler
is written to another file.
But from that other function I'm not able to access the StreamWriter and I don't know how to change the file.
Also I would like to know how I can make the Data in the file accessable during runtime. In my first tests it's always written to the file when I call
file.Close()
b
ut then I cannot open it again.
It would be a great help if anyone could suggest me the way to go...
If I understood your question correctly; the approach you have selected seems to be violating the principle of single responsibility apart from causing you all those issues.
May be what you should consider doing is to create a class that manages the a static instance of stream and use it from open dialog and serial port events
Lets call the stream management class StreamManager. It would have an implementation similer to the following code
public class StreamManager
{
private static StreamWriter file = null;
public void NewFile(string filePath)
{
this.close();
file = new StreamWriter(filePath);
}
public void WriteToFile(string yourData)
{
file.Write(yourData);
}
public void close()
{
if (file != null /* and if not already been closed*/)
{
file.Flush();
file.Close();
}
}
}
Now you may call from new StreamManager().NewFile(fileName) open dialog and new StreamManager ().WriteToFile(…) from serial port.
Please note I have not tested the above code and provided only as a guide. You should add more state / error management to all methods
Cheers
This is a follow on from my last question.
The string I am trying to compare comes through as follows:
Discovered Peripherial: <CBPeripheral: 0x39b8b50 identifier = DEEE65FB-FF1F-A6A9-4C3C-5784F41B0D39, Name = "rawr", state = connecting>
What I'm trying to do is check the identifier number to that which I'm storing in my program. To do that, I have done the following:
private void AppendString(string message)
{
message.Substring(message.Length-77, message.Length);
outputContent.text += "\n" + message;
}
The \n is in there because I'm reading in 6 different devices and they all generate the above line. So I needed something to make it easier to read.
Then in my update function I am checking to see if they are similar like so:
if(String.Equals(myValues["UUID"], outputContent.text, StringComparison.OrdinalIgnoreCase))
{
Instantiate(model1, new Vector3(-2.5f, 3.0f,0), Quaternion.identity);
}
However when I run this on my iPad, xCode generates the following message:
ArgumentOutOfRangeException: startIndex + length > this.length
Parameter name: length
Which I'm guessing means I have miscounted the amount of characters I need to count back from in the substring.
My question is this:
Is there a better way in which I can compare my stored value with that of a specific part of a really long string or have I done something silly in my code which is generating that error?
This is a Unity project which I'm building onto an iPad and makes use of some functionality I can't replicate on a mac.
in your code i observed that you are calling Substring() method but not getting/saving its result into some variable .
message.Substring(message.Length-77, message.Length);
as string is an immutable which can not be modified.
hence when you call the Substring() method it cuts the required text and returns, which you have to save it on some variable to proceed further.
as below:
replace your function AppendString() as below :
private void AppendString(string message)
{
message= message.Substring(message.Length-77, message.Length);
outputContent.text += "\n" + message;
}
No shortage of search for string performance questions out there yet I still can not make heads or tails out of what the best approach is.
Long story short, I have committed to moving from 4NT to PowerShell. In leaving the 4NT I am going to miss the console super quick string searching utility that came with it called FFIND. I have decided to use my rudimentary C# programming skills to try an create my own utility to use in PowerShell that is just as quick.
So far search results on a string search in 100's of directories across a few 1000 files, some of which are quite large, are FFIND 2.4 seconds and my utility 4.4 seconds..... after I have ran mine at least once????
The first time I run them FFIND does it near the same time but mine takes over a minute? What is this? Loading of libraries? File indexing? Am I doing something wrong in my code? I do not mind waiting a little longer but the difference is extreme enough that if there is a better language or approach I would rather start down that path now before I get too invested.
Do I need to pick another language to write a string search that will be lighting fast
I have the need to use this utility to search through 1000 of files for strings in web code, C# code, and another propitiatory language that uses text files. I also need to be able to use this utility to find strings in very large log files, MB size.
class Program
{
public static int linecounter;
public static int filecounter;
static void Main(string[] args)
{
//
//INIT
//
filecounter = 0;
linecounter = 0;
string word;
// Read properties from application settings.
string filelocation = Properties.Settings.Default.FavOne;
// Set Args from console.
word = args[0];
//
//Recursive search for sub folders and files
//
string startDIR;
string filename;
startDIR = Environment.CurrentDirectory;
//startDIR = "c:\\SearchStringTestDIR\\";
filename = args[1];
DirSearch(startDIR, word, filename);
Console.WriteLine(filecounter + " " + "Files found");
Console.WriteLine(linecounter + " " + "Lines found");
Console.ReadKey();
}
static void DirSearch(string dir, string word, string filename)
{
string fileline;
string ColorOne = Properties.Settings.Default.ColorOne;
string ColorTwo = Properties.Settings.Default.ColorTwo;
ConsoleColor valuecolorone = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorOne);
ConsoleColor valuecolortwo = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorTwo);
try
{
foreach (string f in Directory.GetFiles(dir, filename))
{
StreamReader file = new StreamReader(f);
bool t = true;
int counter = 1;
while ((fileline = file.ReadLine()) != null)
{
if (fileline.Contains(word))
{
if (t)
{
t = false;
filecounter++;
Console.ForegroundColor = valuecolorone;
Console.WriteLine(" ");
Console.WriteLine(f);
Console.ForegroundColor = valuecolortwo;
}
linecounter++;
Console.WriteLine(counter.ToString() + ". " + fileline);
}
counter++;
}
file.Close();
file = null;
}
foreach (string d in Directory.GetDirectories(dir))
{
//Console.WriteLine(d);
DirSearch(d,word,filename);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If you want to speed up your code run a performance analysis and see what is taking the most time. I can almost guaruntee the longest step here will be
fileline.Contains(word)
This function is called on every line of the file, on every file. Naively searching for a word in a string can taken len(string) * len(word) comparisons.
You could code your own Contains method, that uses a faster string comparison algorithm. Google for "fast string exact matching". You could try using a regex and seeing if that gives you a performance enhancement. But I think the simplest optimization you can try is :
Don't read every line. Make a large string of all the content of the file.
StreamReader streamReader = new StreamReader(filePath, Encoding.UTF8);
string text = streamReader.ReadToEnd();
Run contains on this.
If you need all the matches in a file, then you need to use something like Regex.Matches(string,string).
After you have used regex to get all the matches for a single file, you can iterate over this match collection (if there are any matches). For each match, you can recover the line of the original file by writing a function that reads forward and backward from the match object index attribute, to where you find the '\n' character. Then output that string between those two newlines, to get your line.
This will be much faster, I guarantee it.
If you want to go even further, some things I've noticed are :
Remove the try catch statement from outside the loop. Only use it exactly where you need it. I would not use it at all.
Also make sure your system is running, ngen. Most setups usually have this, but sometimes ngen is not running. You can see the process in process explorer. Ngen generates a native image of the C# managed bytecode so the code does not have to be interpreted each time, but can be run natively. This speeds up C# a lot.
EDIT
Other points:
Why is there a difference between first and subsequent run times? Seems like caching. The OS could have cached the requests for the directories, for the files, for running and loading programs. Usually one sees speedups after a first run. Ngen could also be playing a part here, too, in generating the native image after compilation on the first run, then storing that in the native image cache.
In general, I find C# performance too variable for my liking. If the optimizations suggested are not satisfactory and you want more consistent performance results, try another language -- one that is not 'managed'. C is probably the best for your needs.
i am very new to C#, and this is my first question, please be gentle on me
I am trying to write a application to capture some tick data from the data provider, below is the main part of the program
void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
{
output myoutput = new output();
myoutput.time = e.TimeStamp;
myoutput.product = e.Product.ToString();
myoutput.type = Enum.GetName(typeof(ZenFire.TickType), e.Type);
myoutput.price = e.Price;
myoutput.volume = e.Volume;
using (StreamWriter writer = File.AppendText("c:\\log222.txt"))
{
writer.Write(myoutput.time.ToString(timeFmt) + ",");
writer.Write(myoutput.product + "," );
writer.Write(myoutput.type + "," );
writer.Write(myoutput.price + ",");
writer.Write(myoutput.volume + ",");
}
i have successfully write the data into the text file, however i know that this method will be call like 10000 times a second during peak time, and open a file and append it many times a second is very inefficient, i was pointed to use a buffer or some sort, but i have no idea how to do it, i try reading the document but i still dont understand, thats why i turn in here for help.
Please give me some (working) snippet code so i can pointed to the write direction. thanks
EDIT: i have simplified the code as much as possible
using (StreamWriter streamWriter = File.AppendText("c:\\output.txt"))
{
streamWriter.WriteLine(string.Format("{0},{1},{2},{3},{4}",
e.TimeStamp.ToString(timeFmt),
e.Product.ToString(),
Enum.GetName(typeof(ZenFire.TickType), e.Type),
e.Price,
e.Volume));
}
ED has told me to make my stream to a field, how is the syntax looks like? can anyone post some code to help me? thanks a lot
You need to create a field for the stream instead of a local variable. Initialize it in constructor once and don't forget to close it somewhere. It's better to implement IDisposable interface and close the stream in Dispose() method.
IDisposable
class MyClass : IDisposable {
private StreamWriter _writer;
MyClass() {
_writer = File.App.....;
}
void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
{
output myoutput = new output();
myoutput.time = e.TimeStamp;
myoutput.product = e.Product.ToString();
myoutput.type = Enum.GetName(typeof(ZenFire.TickType), e.Type);
myoutput.price = e.Price;
myoutput.volume = e.Volume;
_writer.Write(myoutput.time.ToString(timeFmt) + ",");
_writer.Write(myoutput.product + "," );
_writer.Write(myoutput.type + "," );
_writer.Write(myoutput.price + ",");
_writer.Write(myoutput.volume + ",");
}
public void Dispose() { /*see the documentation*/ }
}
There are many things you can do
Step 1. Make sure you don't make many io calls and string concatenations.
Output myOutput = new Outoput(e); // Maybe consruct from event args?
// Single write call, single string.format
writer.Write(string.Format("{0},{1},{2},{3},{4},{5}",
myOutput.Time.ToString(),
myOutput.Product,
...);
This I recommend regardless of what your current performance is. I also made some cosmetic changes (variable/property/class name casing. You should look up the difference between variables and properties and their recommended case etc.)
Step 2. Analyse your performance to see if it does what you want. If it does, no need to do anything further. If performance is still too bad, you can
Keep the file open and close it when your handler shuts down.
Write to a buffer and flush it at regular intervals.
Use a logger framework like log4net that internally handles the above for you, and takes care of hairy issues like access to the log file from multiple threads.
I would use String.Format:
using (StreamWriter writer = new StreamWriter(#"c:\log222.txt", true))
{
writer.AutoFlush = true;
writer.Write(String.Format("{0},{1},{2},{3},{4},", myoutput.time.ToString(timeFmt),
myoutput.product, myoutput.type, myoutput.price, myoutput.volume);
}
If you use # before string you don't have to use double \.
This is much faster - you write only once to the file instead of 5 times. Additionally you don't use + operator with strings which is not the fastest operation ;)
Also - if this is multithreading application - you should consider using some lock. It would prevent application from trying to write to the file from eg. 2 threads at one time.