I am writing a PowerPoint add-in that FTPs a file that has been converted to a WMV.
I have the following code which works fine:
oPres.CreateVideo(exportName);
oPres.SaveAs(String.Format(exportPath, exportName),PowerPoint.PpSaveAsFileType.ppSaveAsWMV,MsoTriState.msoCTrue);
But this kicks off a process within PP which does the file conversion and it immediately goes to the next line of code before the file has finished being written.
Is there a way to detect when this file has finished being written so I can run the next line of code knowing that the file has been finished?
When a file is being used it is unavailable, so you could check the availability and wait until the file is available for use. An example:
void AwaitFile()
{
//Your File
var file = new FileInfo("yourFile");
//While File is not accesable because of writing process
while (IsFileLocked(file)) { }
//File is available here
}
/// <summary>
/// Code by ChrisW -> http://stackoverflow.com/questions/876473/is-there-a-way-to-check-if-a-file-is-in-use
/// </summary>
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
Related
I'm working on converting some files, but I'm having some issues on the 2nd step of this.
Load file from source location
Save file to temp folder
Save converted file to Output location
I have 2 methods for reading the original file, but there is a problem with both of them.
Method 1: The file remains locked (so when something goes wrong, I have to restart the app)
Method 2: The temp file is empty
Anybody got an idea on how to fix one of those problems?
Utilities class
/// <summary>
/// Get document stream
/// </summary>
/// <param name="DocumentName">Input document name</param>
public static Stream GetDocumentStreamFromLocation(string documentLocation)
{
try
{
//ExStart:GetDocumentStream
// Method one: works, but locks file
return File.Open(documentLocation, FileMode.Open, FileAccess.Read);
// Method two: gives empty file on temp folder
using (FileStream fsSource = File.Open(documentLocation, FileMode.Open, FileAccess.Read))
{
var stream = new MemoryStream((int)fsSource.Length);
fsSource.CopyTo(stream);
return stream;
}
//ExEnd:GetDocumentStream
}
catch (FileNotFoundException ioEx)
{
Console.WriteLine(ioEx.Message);
return null;
}
}
/// <summary>
/// Save file in any format
/// </summary>
/// <param name="filename">Save as provided string</param>
/// <param name="content">Stream as content of a file</param>
public static void SaveFile(string filename, Stream content, string location = OUTPUT_PATH)
{
try
{
//ExStart:SaveAnyFile
//Create file stream
using (FileStream fileStream = File.Create(Path.Combine(Path.GetFullPath(location), filename)))
{
content.CopyTo(fileStream);
}
//ExEnd:SaveAnyFile
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
I Call the following functions as following:
public static StreamContent Generate(string sourceLocation)
{
// Get filename
var fileName = Path.GetFileName(sourceLocation);
// Create tempfilename
var tempFilename = $"{Guid.NewGuid()}_{fileName}";
// Put file in storage location
Utilities.SaveFile(tempFilename, Utilities.GetDocumentStreamFromLocation(sourceLocation), Utilities.STORAGE_PATH);
// ... More code
}
In order to copy the source file to a temp folder, the easiest way is to use the File.Copy method from the System.IO namespace. Consider the following:
// Assuming the variables have been set as you already had, this creates a copy in the intended location.
File.Copy(documentLocation, filename);
After some further digging. I found out that you can add a property in the File.Open that "fixes" this issue:
return File.Open(documentLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
With the downside that you still can't move / rename the file, but the lock is removed.
I'm monitoring a folder for new files, and when the new file is present I read (and save in a txt) the file as following:
FileStream file = File.Open(this.filePath, FileMode.Open, FileAccess.Read);
StreamReader reader = new System.IO.StreamReader(file);
string text = reader.ReadToEnd();
reader.Close();
If I copy/paste in the folder the source file, I receive an IOExcpetion that tells me that the file is used by another process.
If I cut/paste in the folder, all works.
Moreover locking problem happens also If I copy (but also cut in this case)/paste the file from another machine into the monitored folder.
Do you have an idea about what is happening?
There is a safer way to access to the file in order to avoid this type of locks?
Thanks!
Here is a little snippet I do to ensure the file is finished copying or not in use by another process.
private bool FileUploadCompleted(string filename)
{
try
{
using (FileStream inputStream = File.Open(filename, FileMode.Open,
FileAccess.Read,
FileShare.None))
{
return true;
}
}
catch (IOException)
{
return false;
}
}
Then you can implement this before your process logic
while (!FileUploadCompleted(filePath))
{
//if the file is in use it will enter here
//So you could sleep the thread here for a second or something to allow it some time
// Also you could add a retry count and if it goes past the allotted retries you
// can break the loop and send an email or log the file for manual processing or
// something like that
}
I'm stuck with a weird problem (which is probably my lack of knowledge), I present the offending code:
try
{
f.Delete();
fTemp.MoveTo(f.FullName);
Console.WriteLine("INFO: Old file deleted new file moved in > {0}", f.FullName);
}
catch (IOException ex)
{
Console.WriteLine("ERROR: Output file has IO exception > {0}", f.FullName);
Environment.ExitCode = 1;
}
f and fTemp are FileInfo objects. So if I run this with code where f is a video file playing in a mediaplayer it throws the exception. That works fine and as expected. Now when I close the mediaplayer it deletes the file!? Even though my application is long closed. Even when I close Visual Studio it still deletes the file, when I close the mediaplayer. As if some callback is being setup somewhere to make sure the file gets deleted at some point. This offcourse in unwanted behaviour. But I can't figure out what exactly goes wrong...
Result for now :
if (!IsFileLocked(f))
{
try
{
f.Delete();
fTemp.MoveTo(f.FullName);
Console.WriteLine("INFO: Old file deleted new file moved in > {0}", f.FullName);
}
catch (IOException ex)
{
Console.WriteLine("ERROR: Output file has IO exception > {0}", f.FullName);
Environment.ExitCode = 1;
}
catch (UnauthorizedAccessException ex)
{
Environment.ExitCode = 2;
Console.WriteLine("ERROR: Output file is locked > {0}", f.FullName);
}
}
else
{
Environment.ExitCode = 3;
Console.WriteLine("ERROR: Couldn't delete file was locked");
}
I know I still can do better between Delete and MoveTo, but I'll take my changes for now, shotgun coding.....
You are getting the IOException because the file cannot immediately be deleted or written to. However, when you call Delete(), it seems the file is getting called for deletion.
Though the media player stops the file from being deleted while it is open, the file is still marked for deletion when it closes, regardless of whether your program is running. So when the media player closes the file is deleted.
You can check if the file is in use with the following code, taken from here. Make the Delete and Copy conditional on it not being locked, and you should be good.
try
{
if(!IsFileLocked(f))
{
f.Delete();
fTemp.MoveTo(f.FullName);
Console.WriteLine("INFO: Old file deleted new file moved in > {0}", f.FullName);
}
}
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
From the Windows SDK:
The DeleteFile function marks a file for deletion on close. Therefore, the file deletion does not occur until the last handle to the file is closed. Subsequent calls to CreateFile to open the file fail with ERROR_ACCESS_DENIED.
As far as I understand, you want your program to wait until the file can be deleted and then delete it and move the other file.
To do this, you could check, if there is a handle open on the file, but this needs unmanaged code. Another way would be to use the methode from the answer of this question: Is there a way to check if a file is in use?
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
Before you start to delete the file you could
A) loop until the file can be deleted
while(IsFileLocked(f)) { Thread.Sleep(100); }
or B) cancel
if (IsFileLocked(f)) { return; }
If you choose A or B depends on your requirements.
I want to check whether a particular Excel file is already opened. Otherwise when I reopen same file in my C# program it is opening in read only format. Is there any way to find out if the file is already open?
If the file if opened by another program this code can help you figure it out, but you won't be able to open it
<!-- language: c# -->
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
(BUt you can't do anything with it, the file must be closed from the program, which opened it)
How do I open (using c#) a file that is already open (in MS Word, for instance)? I thought if I open the file for read access e.g.
FileStream f= new FileStream('filename', FileMode.Open, FileAccess.ReadWrite);
I should succeed, but I get an exception:
"the process cannot access the file
because it is locked ..."
I know there must be a way to read the file irrespective of any locks placed on it, because I can use windows explorer to copy the file or open it using another program like Notepad, even while it is open in WORD.
However, it seems none of the File IO classes in C# allows me to do this. Why?
You want to set FileAccess=Read and FileShare=ReadWrite. Here is a great article on this (along with an explanation of why):
http://coding.infoconex.com/post/2009/04/How-do-I-open-a-file-that-is-in-use-in-C.aspx
Your code is using the FileAccess.Read*Write* flag. Try just Read.
I know this is an old post. But I needed this and I think this answer can help others.
Copying a locked file the way the explorer does it.
Try using this extension method to get a copy of the locked file.
Usage example
private static void Main(string[] args)
{
try
{
// Locked File
var lockedFile = #"C:\Users\username\Documents\test.ext";
// Lets copy this locked file and read the contents
var unlockedCopy = new
FileInfo(lockedFile).CopyLocked(#"C:\Users\username\Documents\test-copy.ext");
// Open file with default app to show we can read the info.
Process.Start(unlockedCopy);
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
}
}
Extension method
internal static class LockedFiles
{
/// <summary>
/// Makes a copy of a file that was locked for usage in an other host application.
/// </summary>
/// <returns> String with path to the file. </returns>
public static string CopyLocked(this FileInfo sourceFile, string copyTartget = null)
{
if (sourceFile is null)
throw new ArgumentNullException(nameof(sourceFile));
if (!sourceFile.Exists)
throw new InvalidOperationException($"Parameter {nameof(sourceFile)}: File should already exist!");
if (string.IsNullOrWhiteSpace(copyTartget))
copyTartget = Path.GetTempFileName();
using (var inputFile = new FileStream(sourceFile.FullName, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite))
using (var outputFile = new FileStream(copyTartget, FileMode.Create))
inputFile.CopyTo(outputFile, 0x10000);
return copyTartget;
}
}