how do i start with fresh with a new file - c#

I catch an exception in my code for a wrong file type. Then i would like to change my file and use the correct file. How do i close the execption to look fresh at the new file and process it.
below is my code. one is a main function. the second is a called function.
main function.
//data file process button
private void button9_Click(object sender, EventArgs e)
{
try
{
panel1.Visible = false; // File paths (Admin Access))
panel3.Visible = true; // File process status
label6.Visible = true; // label - File process status
panel4.Visible = false; // Admin authenticate
InitializeFile();
ParseListFileData();
ListArrayFileData();
CleanDesiredData();
GetRRData();
GetLecoData();
//cleanup();
textBox5.Text += "All RR & Leconum data processing from file - " + textfilename + " completed." + "\r\n";
textBox5.Text += "Please click EXIT to close HORIBA program" + "\r\n";
}
catch(IndexOutOfRangeException)
{
//cleanup();
textBox5.Text += "Bad File" + "\r\n";
datafilepath = "";
textBox5.Text += "Select correct file" + "\r\n";
}
}
The Called Function ParseListFileData();
public void ParseListFileData()
{
//Opens file and uses for processing
System.IO.StreamReader sr = new
System.IO.StreamReader(datafilepath);
try
{
//while loop to read file till end of file
while (!sr.EndOfStream)
{
//split data in file into differend fields
var Row = sr.ReadLine();
var values = Row.Split(',');
ColmnA.Add(values[0]);
ColmnB.Add(values[1]);
ColmnC.Add(values[2]);
ColmnD.Add(values[3]);
ColmnE.Add(values[4]);
ColmnF.Add(values[5]);
ColmnG.Add(values[6]);
ColmnH.Add(values[7]);
ColmnI.Add(values[8]);
ColmnJ.Add(values[9]);
ColmnK.Add(values[10]);
ColmnL.Add(values[11]);
ColmnM.Add(values[12]);
ColmnN.Add(values[13]);
}
sr.Close();
sr.Dispose();
}
catch (IndexOutOfRangeException e)
{
sr.Close();
sr.Dispose();
datafilepath = "";
//cleanup();
//print(e.Message.("Error encountered");
textBox5.Text += "File type not correct or missing data in file "+ e + "\r\n";
}
}
As soon as i select a new good working file, the old exception seems closed, but the old file still remains in use and shows an exception at another function. Even though i i use dispose() to close the streamreader resources.
How can i start fresh with a new file.

Im not sure what exactly is the problem, is the file handle not closed.
I see a problem with your code: you try and catch, but only on a specific exception, say you get an ArgumentException, this will not be caught, instead you can use try{}catch{}finaly{}
try
{
/blabla
}
catch (IndexOutOfRangeException e)
{
datafilepath = "";
//cleanup();
//print(e.Message.("Error encountered");
textBox5.Text += "File type not correct or missing data in file "+ e + "\r\n";
}
finaly
{ //this codes always runs wether exception or not.
sr.Close();
sr.Dispose();
}
alternative and easier solution is to use using (which closes disposables automatically when done):
using(var sr = new System.IO.StreamReader(datafilepath);) {
//try catch in here. even is something goes horribly wrong. StreamReader = fileHandle will be closed.
}

Related

C# - Using loop to open dialog box

I'm trying to make a program that loads a configuration file from another application.
If the file exists, it loads it and displays a message, but if the configuration file is not valid, it displays an error message and then opens a dialog box to load the correct file. But if the user reloads the wrong file, the same dialog box should appear again but that's when my code fails.
Similarly, if the file did not exist from the beginning, it displays a dialog box to load the file, but if it is given to cancel the dialog box or an incorrect file is selected again, my code fails.
I know that the solution would be to use loops but I'm not sure how to structure it.
Pd: searchfile() is my function to open dialog box and readconfig() is my function to read config file of another application.
strfilenamepath = #"C:\Users\test\dogs.exe.config";
if (File.Exists(strfilenamepath))
{
onlyFilename = System.IO.Path.GetFileName(strfilenamepath);
textBox1.Text = onlyFilename;
try
{
string[] valores = readConfig(strfilenamepath);
MessageBox.Show(valores[0] + valores[1] + valores[2]);
}
catch (Exception ex)
{
MessageBox.Show("Error loading config file." + ex.Message);
searchFile();
onlyFilename = System.IO.Path.GetFileName(strfilenamepath);
textBox1.Text = onlyFilename;
string[] valores = readConfig(strfilenamepath);
MessageBox.Show(valores[0] + valores[1] + valores[2]);
}
}
else
{
searchFile();
onlyFilename = System.IO.Path.GetFileName(strfilenamepath);
textBox1.Text = onlyFilename;
try
{
readConfig(strfilenamepath);
string[] valores = readConfig(strfilenamepath);
MessageBox.Show(valores[0] + valores[1] + valores[2]);
}
catch (Exception ex)
{
MessageBox.Show("Error loading config file." + ex.Message);
searchFile();
onlyFilename = System.IO.Path.GetFileName(strfilenamepath);
textBox1.Text = onlyFilename;
string[] valores = readConfig(strfilenamepath);
MessageBox.Show(valores[0] + valores[1] + valores[2]);
}
}
It is easier to design it if you extract the reading logic to another method that handles exceptions and returns a Boolean to signal the success and the computed result. The TryDoSomething pattern does exactly this.
In pseudo code
public bool TryReadConfig(string path, out string[] valores)
{
valores = null;
try {
valores = read the values;
return true;
} catch {
Display message;
return false;
}
}
The main loop in pseudo code
strfilenamepath = #"C:\Users\test\dogs.exe.config";
while (true) {
if (File.Exists(strfilenamepath) && TryReadConfig(strfilenamepath, out var valores)) {
Do something with the valores;
break;
}
var ofd = new OpenFileDialog{ ... };
if (ofd.ShowDialog() == DialogResult.OK) {
strfilenamepath = ofd.Filename;
} else {
break; // The user canceled the operation.
}
}
You can do something like this:
try
{
//Code to try open the file to memory
}
catch (Exception ex)
{
while (true)
{
MessageBox.Show(#"Select an valid file");
var path = searchFile();
if (string.IsNullOrWhiteSpace(path))
continue;
try
{
//Code to try open the file to memory
}
catch (Exception ex2)
{
MessageBox.Show(#"The selected file is not valid");
continue;
}
break;
}
}

How do I save continuous console output to a text file in c#?

I'm quite a noob at programming and I've been stuck at this for a while now. I'm using the following code to get continuous data output streamed to a command prompt. How can I ensure that the output gets copied to a text file after closing the prompt manually?
public static void Main(string[] args)
{
Connector connector;
Console.WriteLine("HelloEEG!");
// Initialize a new Connector and add event handlers
connector = new Connector();
connector.DeviceConnected += new EventHandler(OnDeviceConnected);
connector.DeviceConnectFail += new EventHandler(OnDeviceFail);
connector.DeviceValidating += new EventHandler(OnDeviceValidating);
// Scan for devices across COM ports
// The COM port named will be the first COM port that is checked.
connector.ConnectScan("COM40");
// Blink detection needs to be manually turned on
connector.setBlinkDetectionEnabled(true);
Thread.Sleep(400000);
System.Console.WriteLine("Goodbye.");
connector.Close();
Environment.Exit(0);
}
// Called when a device is connected
static void OnDeviceConnected(object sender, EventArgs e)
{
Connector.DeviceEventArgs de = (Connector.DeviceEventArgs)e;
Console.WriteLine("Device found on: " + de.Device.PortName);
de.Device.DataReceived += new EventHandler(OnDataReceived);
}
// Called when scanning fails
static void OnDeviceFail(object sender, EventArgs e)
{
Console.WriteLine("No devices found! :(");
}
// Called when each port is being validated
static void OnDeviceValidating(object sender, EventArgs e)
{
Console.WriteLine("Validating: ");
}
// Called when data is received from a device
static void OnDataReceived(object sender, EventArgs e)
{
Device.DataEventArgs de = (Device.DataEventArgs)e;
DataRow[] tempDataRowArray = de.DataRowArray;
TGParser tgParser = new TGParser();
tgParser.Read(de.DataRowArray);
/* Loops through the newly parsed data of the connected headset*/
// The comments below indicate and can be used to print out the different data outputs.
for (int i = 0; i < tgParser.ParsedData.Length; i++)
{
//string temp = tgParser.ParsedData[1].ToString;
//Console.WriteLine(tgParser.ParsedData.Length + " + " + temp);
if (tgParser.ParsedData[i].ContainsKey("Raw"))
{
//Console.WriteLine("Raw Value:" + tgParser.ParsedData[i]["Raw"]);
//Console.WriteLine("Raw Value:" + tgParser.ParsedData[i]["Raw"]);
}
if (tgParser.ParsedData[i].ContainsKey("PoorSignal"))
{
//The following line prints the Time associated with the parsed data
//Console.WriteLine("Time:" + tgParser.ParsedData[i]["Time"]);
Console.WriteLine("Time:" + tgParser.ParsedData[i]["Time"]);
//A Poor Signal value of 0 indicates that your headset is fitting properly
Console.WriteLine("Poor Signal:" + tgParser.ParsedData[i]["PoorSignal"]);
poorSig = (byte)tgParser.ParsedData[i]["PoorSignal"];
}
if (tgParser.ParsedData[i].ContainsKey("Attention"))
{
//Console.WriteLine("Att Value:" + tgParser.ParsedData[i]["Attention"]);
Console.WriteLine("Att Value:" + tgParser.ParsedData[i]["Attention"]);
}
if (tgParser.ParsedData[i].ContainsKey("Meditation"))
{
//Console.WriteLine("Med Value:" + tgParser.ParsedData[i]["Meditation"]);
Console.WriteLine("Med Value:" + tgParser.ParsedData[i]["Meditation"]);
}
if (tgParser.ParsedData[i].ContainsKey("EegPowerDelta"))
{
//Console.WriteLine("Delta: " + tgParser.ParsedData[i]["EegPowerDelta"]);
Console.WriteLine("Delta: " + tgParser.ParsedData[i]["EegPowerDelta"]);
}
if (tgParser.ParsedData[i].ContainsKey("BlinkStrength"))
{
//Console.WriteLine("Eyeblink " + tgParser.ParsedData[i]["BlinkStrength"]);
Console.WriteLine("Eyeblink " + tgParser.ParsedData[i]["BlinkStrength"]);
}
}
}
It will be much better to log every console output to a file as it happens. Instead of waiting to write to file when the app is closed manually. To save yourself a lot of coding, you can use log4net to handle the logging.
There's several different ways of approaching this, and with a bit of research I'm sure you could find a few, however this is the solution I would use for this particular action :
As Jonesy mentioned in the comments, I would firstly tidy up your Main. Create a separate class to perform the console writeline and the text output at the same time.
In this class perhaps use a loop to output the data to a file as and when it happens, therefore you wouldn't have to code in the logic when the console is closed manually, which in turn would cover unexpected errors and loss of logs.
This might work.
public static void WriteToFileAndConsole()
{
string outFile = "ConsoleOut.txt";
using (FileStream fileStream = new FileStream(outFile, FileMode.OpenOrCreate))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
using (TextWriter originalConsoleOut = Console.Out)
{
Console.SetOut(writer);
Console.WriteLine("Hello To File");
Console.SetOut(originalConsoleOut);
}
}
}
Console.WriteLine("Hello to console only");
}

Save a file and name it at the "Same" time (NAudio), improving the Accuracy

I want to make a wavefile, and write data to it, and i want the filename to be time it began.
I know hot to write to the wave file using Wavewriter, and i know how to name it to the current time, the problem is however, to make it name the file as close as possible to the moment the audio is written.
Currently i have something like this:
private void SaveReceivedAudio(string recieve)
{
try
{
using (var folderBrowser = new FolderBrowserDialog())
{
DialogResult result = folderBrowser.ShowDialog();
if (result == DialogResult.OK)
{
path = Path.GetFullPath(folderBrowser.SelectedPath) + (Path.DirectorySeparatorChar);
waveWriter = new NAudio.Wave.WaveFileWriter(path + recieve + "- " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss-fff") + ".wav", new WaveFormat(48000, 16, 2));
waveWriterYour = new WaveFileWriter(path + Environment.UserName + " - " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss-fff") + ".wav", new WaveFormat(48000, 16, 2));
Record = true;
Recording.ForeColor = System.Drawing.Color.Green;
Recording.Text = "Recording";
}
else
{
Record = false;
Recording.ForeColor = System.Drawing.Color.Red;
Recording.Text = "Not Recording";
}
}
}
catch (Exception e)
{
MessageBox.Show("SaveReceivedAudio: " + e.Message);
}
}
So as you can see i am clicking a button, choosing a directory, then it will create 2 files in this example at the moment it's created, then change Record to True.
However, this isn't accurate at all, it's probably fairly close, but it all depends on how it's executed.
Now, while i am saving another thread is on loop with the current audio data, which looks like this:
private void RecordingQueueThread()
{
byte[] AudioData;
byte[] AudioData2;
while (connect)
{
try
{
if (Queue.TryTake(out AudioData, 300))
{
if (AudioData.Length == 0)
break;
else
{
if (Record)
{
waveWriter.Write(AudioData, 0, AudioData.Length);
waveWriter.Flush();
TestTimer += AudioData.Length;
}
}
}
if (RecQueue.TryTake(out AudioData2, 300))
{
if (AudioData.Length == 0)
break;
else
{
if (Record)
{
waveWriterYour.Write(AudioData, 0, AudioData.Length);
waveWriterYour.Flush();
}
}
}
}
catch (Exception e)
{
MessageBox.Show("Recording: " + e.Message);
}
}
}
Or well, maybe not in a loop, but there are 2 threads feedins this.
But as you can see, as there are 2 threads(or more) that work independetly, the audio will not be at the time of the Date i wrote earlier, it will be a bit later, and it can vary depending on, well, many thing, process time etc.
Which makes this a problem.
Best thing is if i can write the time exactly when the first data is written, i don't know how to do that however.
Any ideas?

Saving a currently opened file without prompts

I am experiencing a problem with saving a currently opened file without it popping up the dialog asking what name to save it under.
To clarify myself a little more, I open a .txt file and work with it, then would like to just click 'Save' and it save the file without popping up a 'Save As' dialog box.
Here is my save code:
private void SaveFile()
{
SaveFileDialog fileChooser = new SaveFileDialog();
fileChooser.Title = "Choose Save Location";
fileChooser.Filter = "Text Files (*.txt)|*.txt";
fileChooser.OverwritePrompt = false; //Removes warning
DialogResult result = fileChooser.ShowDialog();
if (result == DialogResult.Cancel)
{
return;
}
try
{
string fileName = fileChooser.FileName;
output = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write);
fileWriter = new StreamWriter(output);
foreach (Employee emp in employee)
{
fileWriter.WriteLine(emp.Firstname + "," + emp.Lastname + "," + emp.Position + "," + emp.Bmonth + "," + emp.Bday + "," + emp.BYear + "," + emp.Salary + "," + emp.Hiremonth + "," + emp.Hireday + "," + emp.Hireyear);
}
fileWriter.Close();
output.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
fileWriter.Close();
output.Close();
}
}
Everything works great as far as saving it to a .txt file and loading it back in, it's just that popup that irks me.
The fileChooser object is a SaveFileDialog object. You're causing it to display by calling:
DialogResult result = fileChooser.ShowDialog();
If you don't want to show the dialog, just omit the fileChooser code and instead use:
string fileName = strAlreadyKnownFileName;
I'd firstly save the full path of the opened file in some variable lets say:
private string filepath = "path/to/my/file";
Then you need to create a button and call it i.e. "Save" double click on the button and write this simple code to save whatever you want to the current opened file:
as simple as that...
EDIT:
private void SaveFile()
{
//do your loop and stuff in here and finally write your text to the file using this
File.WriteAllText(filepath, yourtexttobesaved);
}

c# Unable to open file for reading

I'm writing a program that uses FileSystemWatcher to monitor changes to a given directory, and when it receives OnCreated or OnChanged event, it copies those created/changed files to a specified directories. At first I had problems with the fact that OnChanged/OnCreated events can be sent twice (not acceptable in case it needed to process 500MB file) but I made a way around this and with what I'm REALLY BLOCKED with is getting the following IOException:
The process cannot access the file 'C:\Where are Photos\bookmarks (11).html' because it is being used by another process.
Thus, preventing the program from copying all the files it should.
So as I mentioned, when user uses this program he/she specifes monitored directory, when user copies/creates/changes file in that directory, program should get OnCreated/OnChanged event and then copy that file to few other directories.
Above error happens in all cases, if user copies few files that needs to overwrite other ones in folder being monitored or when copying bulk of several files or even sometimes when copying one file in a monitored directory.
Whole program is quite big so I'm sending the most important parts.
OnCreated:
private void OnCreated(object source, FileSystemEventArgs e) {
AddLogEntry(e.FullPath, "created", "");
// Update last access data if it's file so the same file doesn't
// get processed twice because of sending another event.
if (fileType(e.FullPath) == 2) {
lastPath = e.FullPath;
lastTime = DateTime.Now;
}
// serves no purpose now, it will be remove soon
string fileName = GetFileName(e.FullPath);
// copies file from source to few other directories
Copy(e.FullPath, fileName);
Console.WriteLine("OnCreated: " + e.FullPath);
}
OnChanged:
private void OnChanged(object source, FileSystemEventArgs e) {
// is it directory
if (fileType(e.FullPath) == 1)
return; // don't mind directory changes itself
// Only if enough time has passed or if it's some other file
// because two events can be generated
int timeDiff = ((TimeSpan)(DateTime.Now - lastTime)).Seconds;
if ((timeDiff < minSecsDiff) && (e.FullPath.Equals(lastPath))) {
Console.WriteLine("-- skipped -- {0}, timediff: {1}", e.FullPath, timeDiff);
return;
}
// Update last access data for above to work
lastPath = e.FullPath;
lastTime = DateTime.Now;
// Only if size is changed, the rest will handle other handlers
if (e.ChangeType == WatcherChangeTypes.Changed) {
AddLogEntry(e.FullPath, "changed", "");
string fileName = GetFileName(e.FullPath);
Copy(e.FullPath, fileName);
Console.WriteLine("OnChanged: " + e.FullPath);
}
}
fileType:
private int fileType(string path) {
if (Directory.Exists(path))
return 1; // directory
else if (File.Exists(path))
return 2; // file
else
return 0;
}
Copy:
private void Copy(string srcPath, string fileName) {
foreach (string dstDirectoy in paths) {
string eventType = "copied";
string error = "noerror";
string path = "";
string dirPortion = "";
// in case directory needs to be made
if (srcPath.Length > fsw.Path.Length) {
path = srcPath.Substring(fsw.Path.Length,
srcPath.Length - fsw.Path.Length);
int pos = path.LastIndexOf('\\');
if (pos != -1)
dirPortion = path.Substring(0, pos);
}
if (fileType(srcPath) == 1) {
try {
Directory.CreateDirectory(dstDirectoy + path);
//Directory.CreateDirectory(dstDirectoy + fileName);
eventType = "created";
} catch (IOException e) {
eventType = "error";
error = e.Message;
}
} else {
try {
if (!overwriteFile && File.Exists(dstDirectoy + path))
continue;
// create new dir anyway even if it exists just to be sure
Directory.CreateDirectory(dstDirectoy + dirPortion);
// copy file from where event occured to all specified directories
using (FileStream fsin = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
using (FileStream fsout = new FileStream(dstDirectoy + path, FileMode.Create, FileAccess.Write)) {
byte[] buffer = new byte[32768];
int bytesRead = -1;
while ((bytesRead = fsin.Read(buffer, 0, buffer.Length)) > 0)
fsout.Write(buffer, 0, bytesRead);
}
}
} catch (Exception e) {
if ((e is IOException) && (overwriteFile == false)) {
eventType = "skipped";
} else {
eventType = "error";
error = e.Message;
// attempt to find and kill the process locking the file.
// failed, miserably
System.Diagnostics.Process tool = new System.Diagnostics.Process();
tool.StartInfo.FileName = "handle.exe";
tool.StartInfo.Arguments = "\"" + srcPath + "\"";
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
string matchPattern = #"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach (Match match in Regex.Matches(outputTool, matchPattern)) {
System.Diagnostics.Process.GetProcessById(int.Parse(match.Value)).Kill();
}
Console.WriteLine("ERROR: {0}: [ {1} ]", e.Message, srcPath);
}
}
}
AddLogEntry(dstDirectoy + path, eventType, error);
}
}
I checked everywhere in my program and whenever I use some file I use it in using block so even writing event to log (class for what I omitted since there is probably too much code already in post) wont lock the file, that is it shouldn't since all operations are using using statement block.
I simply have no clue who's locking the file if not my program "copy" process from user through Windows or something else.
Right now I have two possible "solutions" (I can't say they are clean solutions since they are hacks and as such not desirable). Since probably the problem is with fileType method (what else could lock the file?) I tried changing it to this, to simulate "blocking-until-ready-to-open" operation:
fileType:
private int fileType(string path) {
FileStream fs = null;
int ret = 0;
bool run = true;
if (Directory.Exists(path))
ret = 1;
else {
while (run) {
try {
fs = new FileStream(path, FileMode.Open);
ret = 2;
run = false;
} catch (IOException) {
} finally {
if (fs != null) {
fs.Close();
fs.Dispose();
}
}
}
}
return ret;
}
This is working as much as I could tell (test), but... it's hack, not to mention other deficients.
The other "solution" I could try (I didn't test it yet) is using GC.Collect() somewhere at the end of fileType() method. Maybe even worse "solution" than previous one.
Can someone pleas tell me, what on earth is locking the file, preventing it from opening and how can I fix that? What am I missing to see?
Thanks in advance.
The problem is most likely that the file is still being copied while you already try to access it. This can happen especially on large files.
You can try to check whether the file can be opened with write permissions before you actually start your processing. For details how to do that check here.
If you can influence the process creating the file there might be a better solution. First copy the file with a temporary extension, and then, after the copying is completed, rename it so that the FileSystemWatcher event will be triggered.
You can try with Volume Shadow Copies.
See www.codeproject.com/KB/dotnet/makeshadowcopy.aspx for more details.
FileSystemWatcher events trigger when the file begins the copy, not at the end, so it's common to run into this kind of errors.
Your first approach will work, however, I would recommend spinning the I/O intensive code on another thread, and using an incremental Sleep() instead of the busy waiting you do.
However, if you have access to the software that actually creates the files, the extension changing is a slightly less complicated solution. Just beware, that a xls filter on the FileSystemwatcher will match a file called myfile1.xls.temp, as I found that out the hard way :)

Categories