I have a method in my windows service as follows:
System.IO.File.Copy(path, ConfigurationManager.AppSettings["BulkInsertGiftRegisterCreatorDirectory"] + System.IO.Path.GetFileName(path));
Loyalty.Entity.Base.FileInfo file = new Loyalty.Entity.Base.FileInfo();
file.FileName = path;
request.Object = file;
ResponseBase response = new ResponseBase(request);
RequestConnection connection = new RequestConnection("cn");
FileManager fileManager = new FileManager(request, connection);
response = fileManager.OfflineGiftRegisterBulkInsert();
System.IO.File.Delete(ConfigurationManager.AppSettings["BulkInsertGiftRegisterCreatorDirectory"] + System.IO.Path.GetFileName(path));
// here is the part of stored procedure that uses file
SELECT #SCRIPT= 'BULK INSERT GIFT_CARD.GIFT_TEMP'
+' FROM '''
+ #FILE_PATH
+''' WITH ('
+'FIELDTERMINATOR = '','','
+ 'KEEPNULLS'
+');'
I can delete the file from file system by hand, but this code says me "Ooops! System.IO.IOException: The process cannot access the file 'filename'
because it is being used by another process."
I've searched the similar questions on stackoverflow and else where. But I could not find anything to help me. Copy or Delete methods return void and I have no stream in my code to dispose.
How can I fix it?
Thanks in advance.
Here is a method for you to check if a file is in use:
public static System.Boolean FileInUse(System.String file)
{
try
{
if (!System.IO.File.Exists(file)) // The path might also be invalid.
{
return false;
}
using (System.IO.FileStream stream = new System.IO.FileStream(file, System.IO.FileMode.Open))
{
return false;
}
}
catch
{
return true;
}
}
Also, to wait for a file I have made:
public static void WaitForFile(System.String file)
{
// While the file is in use...
while (FileInUse(file)) ; // Do nothing.
}
I hope this helps!
Before you go looking through the code you might want to use process explorer to Identify what process has the handle. This might rule out some issue you haven't thought of
update
Since you are using a timer you must make sure that your method is reentrant and you don't have any race conditions.. E.g. the timer ticks faster than you can process the event.
See this question
And this answer
Even better solution, is to add this two lines of code before using the function FileInUse that Vercas showed:
GC.Collect();
GC.WaitForPendingFinalizers();
Related
I am attempting to get the metadata from a few music files and failing miserably. Online, there seems to be absolutely NO HOPE in finding an answer; no matter what I google. I thought it would be a great time to come and ask here because of this.
The specific error I got was: Error HRESULT E_FAIL has been returned from a call to a COM component. I really wish I could elaborate on this issue, but I'm simply getting nothing back from the COMException object. The error code was -2147467259, and it in hex is -0x7FFFBFFB, and Microsoft have not documented this specific error.
I 70% sure that its not the file's fault. My code will run through a directory full of music and convert the file into a song, hence the ConvertFileToSong name. The function would not be running if the file were to not exist is what I'm trying to say.
The only thing I can really say is that I'm using Dotnet 6, and have a massive headache.
Well, I guess I could also share another problem I had before this error showed up. Dotnet6 has top level code or whatever its called, this means that I can't add the [STAThread] attribute. To solve this, I simply added the code bellow to the top. Not sure why I have to set it to unknown, but that's what I (someone else on Stack Overflow) have to do. That solved that previous problem that the Shell32 could not start, but could that be causing my current problem? Who knows... definitely not me.
Thread.CurrentThread.SetApartmentState(ApartmentState.Unknown);
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
Here is the code:
// Help from: https://stackoverflow.com/questions/37869388/how-to-read-extended-file-properties-file-metadata
public static Song ConvertFileToSong(FileInfo file)
{
Song song = new Song();
List<string> headers = new List<string>();
// initialise the windows shell to parse attributes from
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = null;
try
{
objFolder = shell.NameSpace(file.FullName);
}
catch (COMException e)
{
int code = e.ErrorCode;
string hex = code.ToString();
Console.WriteLine("MESSAGE: " + e.Message + ", CODE: " + hex);
return null;
}
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// the rest of the code is not important, but I'll leave it there anyway
// pretty much loop infinetly with a counter better than
// while loop because we don't have to declare an int on a new
// line
for (int i = 0; i < short.MaxValue; i++)
{
string header = objFolder.GetDetailsOf(null, i);
// the header does not exist, so we must exit
if (String.IsNullOrEmpty(header)) break;
headers.Add(header);
}
// Once the code works, I'll try and get this to work
song.Title = objFolder.GetDetailsOf(folderItem, 0);
return song;
}
Good night,
Diseased Finger
Ok, so the solution isn't that hard. I used file.FullName which includes the file's name, but Shell32.NameSpace ONLY requires the directory name (discluding the file name).
This is the code that fixed it:
public static Song ConvertFileToSong(FileInfo file)
{
// .....
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = file.DirectoryName;
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// .....
return something;
}
I'm trying to write exception log messages using StreamWriter in my MVC5 web application.
The main method --
public bool WriteApplicationException(string exp_message)
{
try
{
filename = string.Format("LogMessages\\{0}_{1}.log", "Exception", DateTime.Now.ToShortDateString());
string logFilePath = string.Format(Path.Combine(#"{0}\{1}", AppDomain.CurrentDomain.BaseDirectory, filename));
//logFilePath = logFilePath.Replace(#"\\", #"\");
StringBuilder sb = new StringBuilder();
sb.AppendLine("----------------------------------------------------");
sb.AppendLine(DateTime.Now.ToString());
sb.AppendLine(exp_message);
sb.AppendLine("----------------------------------------------------");
//StreamWriter swr = new StreamWriter(logFilePath, true)
using (StreamWriter swr= File.AppendText(logFilePath))
{
swr.Write(sb.ToString());
swr.Flush();
}
return true;
}
catch (Exception exp)
{
return false;
}
}
I am calling it on the override void OnException in my relevant controller class.
The path that's being generated is as such -
drivelabel:\LogProject.UI\LogProject.UI\LogProject.Web\LogMessages\Exception_3/2/2020.log
But the exception that is being thrown is as such -
{"Could not find a part of the path 'drivelabel:\\LogProject.UI\\LogProject.UI\\LogProject.Web\\LogMessages\\Exception_3\\2\\2020.log'."}
So, could there be any read/write permission issue that is preventing this? Or anything with firewall?
The 2nd one is most unlikely. What could it be? Like I said, the path is very much existent and within the project structure itself. Not outside. What issue here? Any idea?
Thanks.
The message is not telling you that you do not have the right permissions, it is telling you that this path or a part of it does not exist. You need to manually , (or programatically) create that path before you can write to ot.
I have an app that reads from text files to determine which reports should be generated. It works as it should most of the time, but once in awhile, the program deletes one of the text files it reads from/writes to. Then an exception is thrown ("Could not find file") and progress ceases.
Here is some pertinent code.
First, reading from the file:
List<String> delPerfRecords = ReadFileContents(DelPerfFile);
. . .
private static List<String> ReadFileContents(string fileName)
{
List<String> fileContents = new List<string>();
try
{
fileContents = File.ReadAllLines(fileName).ToList();
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
return fileContents;
}
Then, writing to the file -- it marks the record/line in that file as having been processed, so that the same report is not re-generated the next time the file is examined:
MarkAsProcessed(DelPerfFile, qrRecord);
. . .
private static void MarkAsProcessed(string fileToUpdate, string
qrRecord)
{
try
{
var fileContents = File.ReadAllLines(fileToUpdate).ToList();
for (int i = 0; i < fileContents.Count; i++)
{
if (fileContents[i] == qrRecord)
{
fileContents[i] = string.Format("{0}{1} {2}"
qrRecord, RoboReporterConstsAndUtils.COMPLETED_FLAG, DateTime.Now);
}
}
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
}
So I do delete the file, but immediately replace it:
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
The files being read have contents such as this:
Opas,20170110,20161127,20161231-COMPLETED 1/10/2017 12:33:27 AM
Opas,20170209,20170101,20170128-COMPLETED 2/9/2017 11:26:04 AM
Opas,20170309,20170129,20170225-COMPLETED
Opas,20170409,20170226,20170401
If "-COMPLETED" appears at the end of the record/row/line, it is ignored - will not be processed.
Also, if the second element (at index 1) is a date in the future, it will not be processed (yet).
So, for these examples shown above, the first three have already been done, and will be subsequently ignored. The fourth one will not be acted on until on or after April 9th, 2017 (at which time the data within the data range of the last two dates will be retrieved).
Why is the file sometimes deleted? What can I do to prevent it from ever happening?
If helpful, in more context, the logic is like so:
internal static string GenerateAndSaveDelPerfReports()
{
string allUnitsProcessed = String.Empty;
bool success = false;
try
{
List<String> delPerfRecords = ReadFileContents(DelPerfFile);
List<QueuedReports> qrList = new List<QueuedReports>();
foreach (string qrRecord in delPerfRecords)
{
var qr = ConvertCRVRecordToQueuedReport(qrRecord);
// Rows that have already been processed return null
if (null == qr) continue;
// If the report has not yet been run, and it is due, add i
to the list
if (qr.DateToGenerate <= DateTime.Today)
{
var unit = qr.Unit;
qrList.Add(qr);
MarkAsProcessed(DelPerfFile, qrRecord);
if (String.IsNullOrWhiteSpace(allUnitsProcessed))
{
allUnitsProcessed = unit;
}
else if (!allUnitsProcessed.Contains(unit))
{
allUnitsProcessed = allUnitsProcessed + " and "
unit;
}
}
}
foreach (QueuedReports qrs in qrList)
{
GenerateAndSaveDelPerfReport(qrs);
success = true;
}
}
catch
{
success = false;
}
if (success)
{
return String.Format("Delivery Performance report[s] generate
for {0} by RoboReporter2017", allUnitsProcessed);
}
return String.Empty;
}
How can I ironclad this code to prevent the files from being periodically trashed?
UPDATE
I can't really test this, because the problem occurs so infrequently, but I wonder if adding a "pause" between the File.Delete() and the File.WriteAllLines() would solve the problem?
UPDATE 2
I'm not absolutely sure what the answer to my question is, so I won't add this as an answer, but my guess is that the File.Delete() and File.WriteAllLines() were occurring too close together and so the delete was sometimes occurring on both the old and the new copy of the file.
If so, a pause between the two calls may have solved the problem 99.42% of the time, but from what I found here, it seems the File.Delete() is redundant/superfluous anyway, and so I tested with the File.Delete() commented out, and it worked fine; so, I'm just doing without that occasionally problematic call now. I expect that to solve the issue.
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
I would simply add an extra parameter to WriteAllLines() (which could default to false) to tell the function to open the file in overwrite mode, and not call File.Delete() at all then.
Do you currently check the return value of the file open?
Update: ok, it looks like WriteAllLines() is a .Net Framework function and therefore cannot be changed, so I deleted this answer. However now this shows up in the comments, as a proposed solution on another forum:
"just use something like File.WriteAllText where if the file exists,
the data is just overwritten, if the file does not exist it will be
created."
And this was exactly what I meant (while thinking WriteAllLines() was a user defined function), because I've had similar problems in the past.
So, a solution like that could solve some tricky problems (instead of deleting/fast reopening, just overwriting the file) - also less work for the OS, and possibly less file/disk fragmentation.
I am trying to create a file with a FileInfo object and I am getting strange behavior.
Here is the gist of what I am doing -
public void CreateLog()
{
FileInfo LogFile = new FileInfo("");
if (!LogFile.Directory.Exists) { LogFile.Directory.Create(); }
if (!LogFile.Exists) { LogFile.Create(); }
if (LogFile.Length == 0)
{
using (StreamWriter Writer = LogFile.AppendText())
{
Writer.WriteLine("Quotes for " + Instrument.InstrumentID);
Writer.WriteLine("Time,Bid Size,Bid Price,Ask Price,Ask Size");
}
}
}
However, when it checks to see the length of the logfile, it says that the file does not exist (I checked - it does exist).
When I substitute LogFile.Length with the following:
File.ReadAllLines(LogFile.FullName).Length;
Then I get an exception that says that it cannot access the file because something else is already accessing it.
BUT, if I do a Thread.Sleep(500) before I do ReadAllLines, then it seems to work fine.
What am I missing?
LogFile.Create() if you user this function ,you may lock the file, so you can use using ,like this
using(LogFile.Create()){}
after that you can use the file again
I am developing a c# application, backend as sqlite.In my application i have an option for clean databse.It means the curren .db file will delete using File.Delete method and again it create empty databse using File.create method.Now let me explain the problem.
To perform cleandatabse task, i have to stop all the process which is running ,after doing that if i click on clean database it is throwing an error that file cannot delete, it is being used by another process.i am able to stop all the thread which is running.
Somehow i am able to find which process is blocikng the file ,
foreach (var process in Process.GetProcesses()) {
var files = GetFilesLockedBy(process);
if (files.Contains(filePath))
{
procs.Add(process);
Console.WriteLine(process.ProcessName);
process.Kill();
File.Delete(filePath);
}
}
But in the above code i used process.Kill, which close the window form which i am running.
without using kill, i tried close and dispose which doesn't work for me.
Can you please help me to release the file from the process without closing the application and then yo delete the db file.
Thank you in advance
Best regards
Sangita.
You should make sure you close every stream you open it:
using (Stream str = File.Create("C:\\h.txt"))
{
// your code here
} // the stream will be automatically closed here
if you don't put this using statement, it will cause you a lot of bugs, even if you close it manually str.Close();
Streamss are disposable types, you must manage their lifetime manually, either by that using syntax, e.g.:
using (StreamReader f = new ...) {
}
... or by doing it more verbosely (this syntax is required if you allocate and delete the Stream in different code-blocks/functions):
try {
StreamReader f = new ...;
...
} finally {
if (null != f) f.Dispose();
}
... or by making the holding class an IDisposable by itself. See also What Your Mother Never Told You About Resource Deallocation.
Interestingly, this seems to be a practical incarnation of one of those https://stackoverflow.com/questions/2245196/c-urban-myths/2245382#2245382 :
0) In C++, you must mess around with pointers, that's old and dangerous, use C#
Gee, #include boost/shared_ptr> or one of the like. Actually, it is often easier to produce mess in your sowonderful C#:
static void Main () {
foo();
bar();
}
static void foo () {
var f = new StreamWriter ("hello.txt");
f.Write ("hello world");
}
static void bar () {
var f = new StreamReader ("hello.txt");
Console.WriteLine (f.ReadToEnd ());
}
"Unhandled IOException: The process cannot access the file 'hello.txt' because it is being used by another process."
Those claims, btw, are often made by those who happen to never have heard of RAII, and about how far you can get without even smart-pointers.
Not sure but you may be calling Kill on the current process.
EDIT : call Delte after the loop.
Try this :
int currentProcessId = Process.GetCurrentProcess().Id;
foreach (var process in Process.GetProcesses()) {
if (process.Id != currentProcessId)
{
var files = GetFilesLockedBy(process);
if (files.Contains(filePath))
{
procs.Add(process);
Console.WriteLine(process.ProcessName);
process.Kill();
}
}
}
File.Delete(filePath);
Moreover Close doesn't terminate the process, you have to call CloseMainWindow or Kill.