System.IO.Exception
-
I am building a Windows Service and keep getting a System.IO.Exception {"The process cannot access the file 'J:\\Projects\\RTalarms_20071008.txt' because it is being used by another process."}. Nothing has the file open. It is just sitting in the directory. The Bolded area is where the error occurs. Any Idea why? :confused: This the code; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.ServiceProcess; using System.Text; using System.IO; using System.Data.SqlClient; namespace MCPAlarmMonitor { public partial class MCPAlarmMonitorService : ServiceBase { public MCPAlarmMonitorService() { InitializeComponent(); } protected override void OnStart(string[] args) { // TODO: Add code here to start your service. fileSystemWatcher1.EnableRaisingEvents = true; } protected override void OnStop() { // TODO: Add code here to perform any tear-down necessary to stop your service. fileSystemWatcher1.EnableRaisingEvents = false; } private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e) { using (StreamReader reader = new StreamReader(e.FullPath)) { string text = reader.ReadLine(); while (text != null) { text = text.TrimEnd(' '); string[] tokens = text.Split(','); InsertRecord(tokens); text = reader.ReadLine(); } } } private void InsertRecord(string[] tokens) { using (SqlConnection connection = new SqlConnection("server=localhost;database=MCPAlarms;integrated security=true")) { SqlCommand command = new SqlCommand(); command.Connection = connection; command.CommandText = "insert into AlarmsList values(@DateTime,@Address,@Location,@State,@notused1,@notused2,@AlarmMessage)"; for (int i = 0; i < 8; i++) { string parameterName = string.Format("@Column{0}", i + 1); string parameterValue = tokens.Length > i ? tokens[i] : string.Empty; command.Parameters.AddWithValue(parameterName, parameterValue);
-
I am building a Windows Service and keep getting a System.IO.Exception {"The process cannot access the file 'J:\\Projects\\RTalarms_20071008.txt' because it is being used by another process."}. Nothing has the file open. It is just sitting in the directory. The Bolded area is where the error occurs. Any Idea why? :confused: This the code; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.ServiceProcess; using System.Text; using System.IO; using System.Data.SqlClient; namespace MCPAlarmMonitor { public partial class MCPAlarmMonitorService : ServiceBase { public MCPAlarmMonitorService() { InitializeComponent(); } protected override void OnStart(string[] args) { // TODO: Add code here to start your service. fileSystemWatcher1.EnableRaisingEvents = true; } protected override void OnStop() { // TODO: Add code here to perform any tear-down necessary to stop your service. fileSystemWatcher1.EnableRaisingEvents = false; } private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e) { using (StreamReader reader = new StreamReader(e.FullPath)) { string text = reader.ReadLine(); while (text != null) { text = text.TrimEnd(' '); string[] tokens = text.Split(','); InsertRecord(tokens); text = reader.ReadLine(); } } } private void InsertRecord(string[] tokens) { using (SqlConnection connection = new SqlConnection("server=localhost;database=MCPAlarms;integrated security=true")) { SqlCommand command = new SqlCommand(); command.Connection = connection; command.CommandText = "insert into AlarmsList values(@DateTime,@Address,@Location,@State,@notused1,@notused2,@AlarmMessage)"; for (int i = 0; i < 8; i++) { string parameterName = string.Format("@Column{0}", i + 1); string parameterValue = tokens.Length > i ? tokens[i] : string.Empty; command.Parameters.AddWithValue(parameterName, parameterValue);
Your code is reacting to the Created event immediately after the file is created, but probably before the file is closed by the process that created it, so yes, the file is being held open with DenyShareAll while it's being written by the other process. By the time you realize it and look at the file, it's done being written and has been closed. That's one of the pitfalls of the FSW. Your code has to be written to retry file operations if your going to start modifying the file while it's still being written. If you can't open the file, you'll have to wait a second and retry the operation. Keep retying until you either reach some retry limit your've put in, or the file successfully opens.
A guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007 -
Your code is reacting to the Created event immediately after the file is created, but probably before the file is closed by the process that created it, so yes, the file is being held open with DenyShareAll while it's being written by the other process. By the time you realize it and look at the file, it's done being written and has been closed. That's one of the pitfalls of the FSW. Your code has to be written to retry file operations if your going to start modifying the file while it's still being written. If you can't open the file, you'll have to wait a second and retry the operation. Keep retying until you either reach some retry limit your've put in, or the file successfully opens.
A guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007So if I insert put a thread sleep entry before this line Thread.Sleep(500); using (StreamReader reader = new StreamReader(e.FullPath)) would that solve it?
-
So if I insert put a thread sleep entry before this line Thread.Sleep(500); using (StreamReader reader = new StreamReader(e.FullPath)) would that solve it?
Since you have no idea how long the other application will have the file open, maybe and maybe not. You will STILL have to repeatedly try to open the file until your either exhaust your retry count or it opens.
A guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007 -
Since you have no idea how long the other application will have the file open, maybe and maybe not. You will STILL have to repeatedly try to open the file until your either exhaust your retry count or it opens.
A guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007With a little experimentation I just kept bumping up the time until I no longer got that error. Now I am getting {"Must declare the scalar variable \"@DateTime\"."}. I am not as savvy with SQL Commands. I am missing something simple I feel.
-
With a little experimentation I just kept bumping up the time until I no longer got that error. Now I am getting {"Must declare the scalar variable \"@DateTime\"."}. I am not as savvy with SQL Commands. I am missing something simple I feel.
That solution will only work so long as the other process cooperates and performs EXACTLY as expected. Once the system gets booged down or the other process changes, your solution breaks instantly. That's why I said you MUST write your code to retry opening the file, NOT wait a predetermined amount of time. Your code is not written defensively and is actually hoping the future NEVER changes. Good luck with that. Your SQL statement is written incorrectly. It's much better practice to specify the column names in your table and then the parameter names assigned to them. If your SQL table changes, it won't immediately break your code. You also have incorrectly created the parmater objects. Change the SQL to: (I'm making assumptions about your column names and types!!)
INSERT INTO AlarmsList (DateTime, Address, Location, State, AlarmMessage)
VALUES (@DateTime,@Address,@Location,@State,@AlarmMessage)The names with the @ in front of them are your parameter place holders. You have to create these exact parameters in your code and give them the appropriate values. BTW, why are you storing your DateTimes as a string in the database?? Bad practice!
command.Parameters.AddWithValue("@DateTime, tokens\[0\]); command.Parameters.AddWithValue("@Address", tokens\[1\]); command.Parameters.AddWithValue("@Address", tokens\[2\]); command.Parameters.AddWithValue("@Address", tokens\[3\]); // 4 and 5 get skipped because you're not using them, so why take up the bandwidth passing them? command.Parameters.AddWithValue("@Address", tokens\[6\]);
Putting in that line with the ?: in it was useless. Go back to the tokenizing code and validate you can fill in all the fields back there.
A guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007 -
That solution will only work so long as the other process cooperates and performs EXACTLY as expected. Once the system gets booged down or the other process changes, your solution breaks instantly. That's why I said you MUST write your code to retry opening the file, NOT wait a predetermined amount of time. Your code is not written defensively and is actually hoping the future NEVER changes. Good luck with that. Your SQL statement is written incorrectly. It's much better practice to specify the column names in your table and then the parameter names assigned to them. If your SQL table changes, it won't immediately break your code. You also have incorrectly created the parmater objects. Change the SQL to: (I'm making assumptions about your column names and types!!)
INSERT INTO AlarmsList (DateTime, Address, Location, State, AlarmMessage)
VALUES (@DateTime,@Address,@Location,@State,@AlarmMessage)The names with the @ in front of them are your parameter place holders. You have to create these exact parameters in your code and give them the appropriate values. BTW, why are you storing your DateTimes as a string in the database?? Bad practice!
command.Parameters.AddWithValue("@DateTime, tokens\[0\]); command.Parameters.AddWithValue("@Address", tokens\[1\]); command.Parameters.AddWithValue("@Address", tokens\[2\]); command.Parameters.AddWithValue("@Address", tokens\[3\]); // 4 and 5 get skipped because you're not using them, so why take up the bandwidth passing them? command.Parameters.AddWithValue("@Address", tokens\[6\]);
Putting in that line with the ?: in it was useless. Go back to the tokenizing code and validate you can fill in all the fields back there.
A guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007The DateTime Column is an odd format from the log file. I think I can figure it out from here. Thanks for you suggestions. Brian