Making Reading of TextFile More efficient (Larger File Type) - c#

The following are my codes but it cant handle more than 500 lines at one time.
It needs to add a , to the end of the line and at the same time detect. What i'm currently doing is separating them into 2 different textbox then save the one which i need by copy pasting but the app seems to hang if the file is too big.
Can someone help me with making it more efficient. Would really appreciate it.
private void button1_Click_1(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
return;
System.IO.StreamReader Reader = new System.IO.StreamReader(openFileDialog1.FileName);
//Create a filestream
FileStream fStr;
try
{
//Set filestream to the result of the pick of the user
fStr = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
//Create a streamreader, sr, to read the file
StreamReader sr = new StreamReader(fStr);
//While the end of the file has not been reached...
while (sr.Peek() >= 0)
{
//Create a 'line' that contains the current line of the textfile
string line = sr.ReadLine().ToLower();
if (line.Contains("staff"))
{
line += ","; //Add a , to the end of the line**Important**
textBox1.Text += line + Environment.NewLine;
releventcount += 1;
}
else
{
line += ","; //Add a , to the end of the line**Important**
textBox2.Text += line + Environment.NewLine;
irreleventcount += 1;
}
label1.Text = "Relevent: ";
label2.Text = "Irrelevant: ";
}
//Close the file so other modules can access it
sr.Close();
//If something goes wrong, tell the user
}
catch (Exception)
{
MessageBox.Show("Error opening file", "Check the CODE ! ~.~");
}
}

I'm not sure what it is you're eventually trying to accomplish here. There are several more succinct ways to do what your current code is doing, but they won't significantly improve the speed of reading.
The bottleneck in your code is that you're appending strings. Using a StringBuilder is good advice, but you can do better than that by creating a List<string> and then calling string.Join at the end. For example:
if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
return;
List<string> staff = new List<string>();
List<string> other = new List<string>();
foreach (var line in File.ReadLines(openFileDialog1.FileName))
{
line = line.ToLower();
if (line.Contains("staff"))
{
staff.Add(line);
}
else
{
other.Add(line);
}
}
relevantcount = staff.Count;
irrelevantCount = other.Count;
textBox1.Text = string.Join(","+Environment.NewLine, staff);
textBox2.Text = string.Join("."+Environment.NewLine, other);
Also, you say that your code can only handle 500 lines at a time. Is there something in your user interface that prevents it from handling more? Certainly, there's nothing in the code you showed that has such a low limit.

500 lines is nothing.
Try File.ReadAllLines and File.WriteAllLines.
Then you can do your work on an array of strings in memory and avoid the iterative IO.

Reading files line by line is very slow. You can make this code much faster by reading a large block of data (or even the entire file if it's not too enormous). For example, use a File.ReadAllLines to read the entire file as separate lines, or use a FileStream and Read() into a buffer, and find the individual lines for yourself by looking for newline (\n, \r) characters.
To export the data, don't copy and paste it fom a text box - Write the results to one or two new files, and then just open them.

It is much, much more efficient to use StringBuilders to gather the text for the textboxes than to continuously append text.
Also, you should wrap your various streams in using blocks.
Here is a rewrite that should be much more efficient:
private void button1_Click_1(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
return;
try
{
//Set filestream to the result of the pick of the user
using (var fStr = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read))
{
//Create a streamreader, sr, to read the file
using (var sr = new StreamReader(fStr))
{
var sbTextBox1 = new System.Text.StringBuilder(10000);
var sbTextBox2 = new System.Text.StringBuilder(10000);
//While the end of the file has not been reached...
while (sr.Peek() >= 0)
{
//Create a 'line' that contains the current line of the textfile
string line = sr.ReadLine().ToLower();
if (line.Contains("staff"))
{
//Add a , to the end of the line**Important**
sbTextBox1.Append(line).Append(",").AppendLine();
releventcount += 1;
}
else
{
//Add a , to the end of the line**Important**
sbTextBox2.Append(line).Append(",").AppendLine();
irreleventcount += 1;
}
}
textBox1.Text = sbTextBox1.ToString();
textBox2.Text = sbTextBox2.ToString();
label1.Text = "Relevent: ";
label2.Text = "Irrelevant: ";
//Close the file so other modules can access it
sr.Close();
}
}
}
catch (Exception)
{
MessageBox.Show("Error opening file", "Check the CODE ! ~.~");
}
}

Related

Read text file line by line using timer

StreamReader sr = new StreamReader("C:/CR EZ Test/Log.txt"); //use with IF
private void timer2_Tick(object sender, EventArgs e)
{
if ((line = sr.ReadLine()) != null)
{
//FileStream fs = File.Open("C:/CR EZ Test/Log.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//StreamReader sr = new StreamReader(fs); //use with While can't use with }else{
//while ((line = sr.ReadLine()) != null)
//{
string[] dataLog = line.Split(new[] { ',' }, StringSplitOptions.None);
mpa = (dataLog[1]);
ml = (dataLog[2]);
lph = (dataLog[3]);
elapsedTime = float.Parse(dataLog[4]) / 1000;
if (testStatus > 0) time = elapsedTime.ToString("0.0");
tb2.Value = int.Parse(dataLog[6]);
if (chart1.Series[0].Points.Count > tb1.Value && tb1.Value > 0)
{
chart1.Series[0].Points.RemoveAt(0);
chart1.Series[1].Points.RemoveAt(0);
}
chart1.Series[0].Points.AddXY(dataLog[5], int.Parse(dataLog[1]));
chart1.Series[1].Points.AddXY(dataLog[5], int.Parse(dataLog[6]));
//}
}
else
{
sr.DiscardBufferedData();
sr.BaseStream.Seek(0, SeekOrigin.Begin);
sr.BaseStream.Position = 0;
//sr.Close();
//alertTB.Text = "";
timer2.Enabled = false;
}
alertTB.ForeColor = Color.Red;
alertTB.Text = "Data Log Viewing In Progress";
}
The issue is I am reading a text file full of variables back through a GUI, like replaying a video. As the code is shown, it works and I can control the timer tick to change the replay speed. The issue is the file is in use, so I can't write to or delete the text while the file is in use, without closing it first. I would like to either be able to find a workaround of the Streamreader, or use the Filestream to Streamreader code that will allow me to edit the file while it is in use. The issue there is, I can't figure out how to make it work with the timer, it just reads the entire file very quickly. Any help or ideas are greatly appreciated.
The issue here is how to have the commented out code to:
read a line of the text file,
have the timer to tick
then read the next line of the text file, and so on. Obviously handling the data as it arrives.
Opening a file while it is in use
I think what you are looking for is FileStream with FileShare.ReadWrite for the instance of your StreamReader (not the instance you have commented out),
var fs = new FileStream("C:\foo.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var sr = new StreamReader(fs);
Setting the position of the stream
It also seems like based on your comments, you are having trouble with positioning the stream, this is how you could do that...
fs.Position = 0; // note this is the FileStream not the StreamReader!
// alternatively, you could use Seek
Difference between sequential and random access
Lastly, you might want to take a look below to see the difference between sequential and random access
A Potential Solution
Here is a class called FileMonitor that will check the file and update the list whenever the file is changed / updated.
I understand that you want a timer to poll the data in the text file, but in case the timer is very fast, I have optimized the FileMonitor to watch the file for changes and only extract when there is a change.
Please note that this only continues to read where it was left off, based on the position of the stream. So, it will not work if lines are deleted or modified prior to getting "extracted". This means it only functions based on your requirements and is not improved to handle a lot of other scenarios, but it should adequately cover your requirements.
public class FileMonitor : IDisposable
{
private readonly FileStream _file;
private readonly StreamReader _reader;
private long _position;
private List<string> _lines;
public FileMonitor(string file)
{
if (String.IsNullOrEmpty(nameof(file))) throw new ArgumentNullException(nameof(file));
_lines = new List<string>();
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = Path.GetDirectoryName(file);
watcher.Filter = Path.GetFileName(file);
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Changed += new FileSystemEventHandler(OnChanged);
//watcher.Created += new FileSystemEventHandler(OnCreated);
//watcher.Deleted += new FileSystemEventHandler(OnDeleted);
//watcher.Renamed += new RenamedEventHandler(OnRenamed);
// begin watching.
watcher.EnableRaisingEvents = true;
// begin reading
_file = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
_reader = new StreamReader(_file);
_lines = ReadLines(_reader).ToList();
_position = _file.Position;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
List<string> update = ReadLines(_reader).ToList();
// fix to remove the immidate newline
if (update.Count() > 0 && String.IsNullOrEmpty(update[0])) update.RemoveAt(0);
_lines.AddRange(update);
_position = _file.Position;
// just for debugging, you should remove this
Console.WriteLine($"File: {e.FullPath} [{e.ChangeType}]");
}
public IEnumerable<string> Lines { get { return _lines; } }
public void Reset()
{
_file.Position = 0;
_position = _file.Position;
_lines.Clear();
}
private static IEnumerable<string> ReadLines(StreamReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
public void Dispose()
{
_reader.Dispose();
_file.Dispose();
}
}
Here is how you could use it with your timer
private IEnumerable<string> _lines; // holds all the lines "extracted"
void Main()
{
string file = #"C:\Data\foo.txt";
using (var timer = new System.Timers.Timer())
{
timer.Interval = 2000; // 2 second interval
timer.Elapsed += OnTimedEvent; // attach delegate
timer.Enabled = true; // start the timer
// open the file
using (var monitor = new FileMonitor(file))
{
_lines = monitor.Lines;
// loop forever, remove this
while (true) { }
}
}
}
public void OnTimedEvent(object sender, EventArgs e)
{
// just for debugging, you should remove this
Console.WriteLine($"current count: {_lines.Count()}");
}
If it isn't clear, the data extracted is held in a list of strings. Above, you can grab the "extracted" data from the monitor using the monitor.Line property.
A Proven Working Solution
string line;
if (!File.Exists(logFile))
{
viewLog.Text = "Play";
alertTB.ForeColor = Color.Red;
alertTB.Text = "File Does Not Exist | Log Data To Create File";
chart.Text = "Scope On";
}
if (File.Exists(logFile))
{
var lineCount = File.ReadLines(logFile).Count();//read text file line count to establish length for array
if (lineCount < 2)
{
viewLog.Text = "Play";
alertTB.ForeColor = Color.Red;
alertTB.Text = "File Exists | No Data Has Been Recorded";
chart.Text = "Scope On";
}
if (counter < lineCount && lineCount > 0)//if counter is less than lineCount keep reading lines
{
line = File.ReadAllLines(logFile).Skip(counter).Take(lineCount).First();
string[] dataLog = line.Split(new[] { ',' }, StringSplitOptions.None);
//-----------------------------------------Handling my data
counter++;
}
else
{
counter = 0;
timer2.Enabled = false;
}
}
This is the fix I arrived at, it allows editing the file or deleting the contents of the file. I get the line count before trying to load the file. I then use the counter to iterate through the lines. I can change the delay between the next line read based upon the timer tick interval, pause it, or stop it.

C# Visual Studio - I'm trying to read a text file and display it into Richtextbox and include new lines

I'm trying to read a text file and display it into Richtextbox and include new lines.
Say I want it to read as:
Hello
Hello
Hello
But it is reading as:
HelloHelloHello
This is the code that I have so far:
private void btnView_Click(object sender, EventArgs e)
{
OpenFileDialog op = new OpenFileDialog();
op.InitialDirectory = "C:\\";
op.Filter = "Txt files (*.txt)|*.txt|All Files (*.*)|*.*";
op.FilterIndex = 2;
if (op.ShowDialog() == DialogResult.OK)
{
textBox1.Text = op.FileName;
string path = op.FileName;
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(path))
{
while(sr.Peek() >= 0)
{
sb.Append(sr.ReadLine());
Console.WriteLine("\r\n");
}
}
richTextBox1.Text = sb.ToString();
}
}
StreamReader lines are delimited by Environment.NewLine. If you'd read the documentation you would have noticed ReadLine does not include these delimiters. If you want to re-add them use:
sb.Append(sr.ReadLine());
sb.Append(Environment.NewLine);
And don't call Console.WriteLine() in a WinForms app.
Another way you can do it is to use the File class's static ReadAllText() method.
You just pass it the path to a text file, and it will read all the text (line breaks included) into a string and return it to you. Then you can just set the result of that to your richTextBox1.Text property for some much cleaner and easier to read code:
if (op.ShowDialog() == DialogResult.OK)
{
textBox1.Text = op.FileName;
richTextBox1.Text = File.ReadAllText(op.FileName);
}
change the line:
Console.WriteLine("\r\n");
to:
sb.Append("/r/n");

Selenium find array contents on page

I'm using Visual Studio with Selenium to build an application that goes to a web page and finds if the contents of an array are on the page. I'm running into an issue with searching the page for the array contents.. Right now it finds nothing, so it clicks to go to the next page when it shouldn't.
The array comes from a CSV file I'm loading in and it needs to search the page for a match of any of the records from the CSV file and stops.
Here is what I have so far:
OpenFileDialog ofd = new OpenFileDialog();
private double timeOut;
private void bttnImportBrowse_Click(object sender, EventArgs e)
{
ofd.Filter = "CSV|*.csv";
var fileInputs = new List<string>();
if (ofd.ShowDialog() == DialogResult.OK)
{
String chosenFile = ofd.FileName;
String safeFileName = ofd.SafeFileName;
try
{
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(chosenFile))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
//Console.WriteLine(line);
fileInputs.Add(line);
//Console.Write(string.Join(" ", fileInputs));
var driver = new ChromeDriver(#"C:\Users\andre_000\Documents\Visual Studio 2015\Projects\MyProject\");
driver.Navigate().GoToUrl("MySite");
var WebDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.XPath("/html/body/a[2]"))));
while (1==1) {
try
{
var result = driver.FindElement(By.LinkText(fileInputs.ToString()));
break;
}
catch (NoSuchElementException n)
{
var nextBttn = driver.FindElementByXPath("/html/body/a[2]");
nextBttn.Click();
}
}
}
}
}
catch (Exception entry)
{
// Let the user know what went wrong.
Console.WriteLine("The file could not be read:");
Console.WriteLine(entry.Message);
}
}
}
Sorry i would have left a comment but am not allowed to yet. Do you have the CSV file?
I believe you are trying to find the Link text incorrectly.
Currently calling ToString() on the list
var result = driver.FindElement(By.LinkText(fileInputs.ToString()));
should probably be
var result = driver.FindElement(By.LinkText(line));

Save a state of checkbox to specific line of file C #

I've searched multiple solutions and coudnt find the one specificly adressing my issue:
What i want to accomplish is to save a state of checkbox to specific line of file.
I have used identical code for saving patch of file from openFileDialog.
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
var lines = File.ReadAllLines("patcher.conf");
lines[0] = openFileDialog1.FileName;
File.WriteAllLines("patcher.conf", lines);
}
code above saves file patch in 1st (0 indexed) line of text file, and it works!
But for some reason when i try to do exacly the same thing in :
private void checkexe_CheckedChanged(object sender, EventArgs e)
{
string line;
System.IO.StreamReader file =
new System.IO.StreamReader("patcher.conf");
while ((line = file.ReadLine()) != null)
{
var lines = File.ReadAllLines("patcher.conf");
lines[1] = checkexe.Checked.ToString();
File.WriteAllLines("patcher.conf", lines);
}
file.Close();
}
and save information about state of checkbox in 2nd (1 indexed line of file) the error says :
process cannot access the file because it is being used by another process.
What i do wrong?
Your method for writing the file is flawed. You are opening the file and reading all lines, but for every line, you are then reading all lines again and saving the file in the same loop. This would be the cause of your process cannot access the file because it is being used by another process error.
private void checkexe_CheckedChanged(object sender, EventArgs e)
{
string line;
System.IO.StreamReader file = new System.IO.StreamReader("patcher.conf");
while ((line = file.ReadLine()) != null)
{
var lines = File.ReadAllLines("patcher.conf");
lines[1] = checkexe.Checked.ToString();
File.WriteAllLines("patcher.conf", lines);
}
file.Close();
}
Instead, try below: (untested, but should get you in the right direction)
private void checkexe_CheckedChanged(object sender, EventArgs e)
{
var lines = File.ReadAllLines("patcher.conf");
for(var i = 0; i < lines.Length; i++)
{
if (i == 1)
lines[i] = checkexe.Checked.ToString();
}
File.WriteAllLines("patcher.conf", lines);
}
On the file stream, you have use readwrite
System.IO.FileStream fs = new System.IO.FileStream(txtFilePath.Text, System.IO.FileMode.Open, System.IO.FileAccess.Read,System.IO.FileShare.ReadWrite);
System.IO.StreamReader sr = new System.IO.StreamReader(fs);

How to open a program if the .txt doesn't exist yet?

I've got this code at the start of the form that reads a file that already exists and sets value of 4 textBoxes accordingly to what it's written inside. How do I proceed if the file hasn't yet been created? Any help would be very appreciated.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FileStream file = new FileStream("cenaEnergentov.txt", FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(file);
sr.ReadLine();
var textLines = File.ReadAllLines("cenaEnergentov.txt");
foreach (var line in textLines)
{
string[] dataArray = line.Split(';');
textBox1.Text = (dataArray[0]);
textBox2.Text = (dataArray[1]);
textBox3.Text = (dataArray[2]);
textBox4.Text = (dataArray[3]);
}
}
If the uper is a false I'd like to proceed with normal script down below that starts with:
public void trackBar1_Scroll(object sender, EventArgs e)
{
......
Use a simple if statement
// I edit this line according to your comment
if(File.Exists(String.Concat("cenaEnergentov".ToUpper(), ".txt"))
{
// do your job
}
else
{
// call appropriate method
trackBar1_Scroll(this,EventArgs.Empty); // for example
}
Try this before you open the file:
var filename = "filename.txt";
if (!File.Exists(filename))
{
File.Create(filename);
}
This won't account for the fact that you're assigning values without checking to see if they exist first. Implementing that is relatively trivial as well.
It also appears that the FileStream and StreamReader are redundant. Just use File.ReadAllLines instead.
The previous solutions will work OK... however they don't really answer the big question:
How do I know when to continue?
The best way would be to use a FileSystemWatcher:
var watcher = new FileSystemWatcher(path, ".txt");
watcher.Created += (sender, e) =>
{
if (e.ChangeType == WatcherChangeTypes.Created)
initForm();
};
Where initForm() is:
void initForm()
{
if(File.Exists(path))
{
// Update form
}
else
{
var watcher = new FileSystemWatcher(path, ".txt");
watcher.Created += (sender, e) =>
{
if (e.ChangeType == WatcherChangeTypes.Created)
initForm();
};
}
}
try this
if(File.Exists("yourFile.txt"))
{
//do what you do
}
else
{
// call appropriate method
}

Categories

Resources