If a file is open by another application, and then I try to save it through the Silverlight SaveDialog, I can catch the error with an exception but after that I get this error.
Line: 57
Error: Unhandled Error in Silverlight Application
Code: 4004
Category: ManagedRuntimeError
Message: System.InvalidOperationException: This operation can only occur on the UI Thread.
at System.Windows.Hosting.NativeHost.VerifyThread()
at System.Windows.SaveFileStream.Dispose(Boolean disposing)
at System.IO.FileStream.Finalize()
I would prefer to detect that the file is open, but can't seem to do that. I tried fs.CanWrite, but it returns true, even when the file is open by another application.
EDIT: Here is a post on the silverlight forum that seems to explain what is happening, although they think it's just Office files. I'm having the problem with a PDF file.
Here is my code:
public void PDFSaveFile(bool success)
{
// silverlight requires saveFileDialog to be user-initiated,
// so this is called from the OK button of a pop-up window
// ignore success, we only gave an OK option
byte[] fileBytes = doc.ToPDF().ToArray();
PDFClose();
try
{
SaveFileDialog saveFileDlg = new SaveFileDialog();
saveFileDlg.Filter = "PDF files (*.pdf)|*.pdf";
bool? dialogResult = saveFileDlg.ShowDialog();
if (dialogResult == true)
{
using (var fs = saveFileDlg.OpenFile())
{
fs.Write(fileBytes, 0, fileBytes.Length);
fs.Close();
}
}
}
catch (Exception ex)
{
Log.HandleInternalError(string.Format("Unable to save file: {0}",ex.Message));
}
}
You can use
FileInfo.Open
if return a IOException = File already opened
FileInfo.Open
Related
This question already has answers here:
save file to my documents
(2 answers)
Closed 1 year ago.
I have a function that writes a html file and opens it to a web browser. However when I package and deploy the application it will not open and says access denied. I am told I need to write the html file to the computers mydocuments and open it there. Any ideas on how to do this so I can get around this permission error? Here is my function that writes the html file:
private void PrintReport(StringBuilder html)
{
// Write (and overwrite) to the hard drive using the same filename of "Report.html"
try
{
// A "using" statement will automatically close a file after opening it.
// It never hurts to include a file.Close() once you are done with a file.
using (StreamWriter writer = new StreamWriter("Report.html"))
{
writer.WriteLine(html);
}
System.Diagnostics.Process.Start(#"Report.html"); //Open the report in the default web browser
}
catch (Exception ex)
{
MessageBox.Show(message + ex.Message, "Program Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void PrintReport(StringBuilder html)
{
// Write (and overwrite) to the hard drive using the same filename of "Report.html"
try
{
// A "using" statement will automatically close a file after opening it.
// It never hurts to include a file.Close() once you are done with a file.
using (StreamWriter writer = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Report.html"))
{
writer.WriteLine(html);
}
System.Diagnostics.Process.Start(#"Report.html"); //Open the report in the default web browser
}
catch (Exception ex)
{
MessageBox.Show(message + ex.Message, "Program Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
I am running into a problem where I am using IText 7 to check a PDF that a user has downloaded off the internet.
For my test case I created a text file with garbage in it and saved it as a pdf. I know its not valid.
In the code I am trying to open the PDF using PDFReader.
An exception is being thrown, this is expected.
When debugging the code the Reader object is null when it gets to the finally spot. So the
reader.close() isn't even firing.
I am even copying the file to a temp directory just to ensure nothing else is holding the file.
I am then unable to delete the PDF file either in code or manually in a file explorer after the exception.
Here is some of my code. I removed everything but the Reader part. Also this code is after I have tried a few things, so you are seeing my attempt with the file being copied to a temp file. I am attempted to delete the temp file in the finally part. That is failing on a corrupt file.
Here are both the exceptions that are thrown when attempting to validate a bad PDF. The first is from the PDFReader call.
2021-04-09 13:18:11,079 ERROR GUI.Form1 - PDF header not found.
iText.IO.IOException: PDF header not found. at
iText.IO.Source.PdfTokenizer.GetHeaderOffset() at
iText.Kernel.Pdf.PdfReader.GetOffsetTokeniser(IRandomAccessSource> byteSource) at
iText.Kernel.Pdf.PdfReader..ctor(String filename, ReaderProperties properties) at
iText.Kernel.Pdf.PdfReader..ctor(FileInfo file) at
GUI.Form1.validatePDF(FileInfo pdfFile, HashSet`1 tmpMd5s)
The Second is from the attempt to delete the temp file
2021-04-09 13:18:11,116 ERROR GUI.Form1 - The process cannot access the file
'C:\Users\ret63\AppData\Local\Temp\tmp27DE.tmp' because it is being used by another process.
System.IO.IOException: The process cannot access the file 'C:\Users\ret63\AppData\Local\Temp\tmp27DE.tmp' because it is being used by another process. at
System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileInfo.Delete() at
GUI.Form1.validatePDF(FileInfo pdfFile, HashSet`1 tmpMd5s)
PdfDocument pdfDoc = null;
PdfReader reader = null;
try
{
using (reader = new PdfReader(testFile))
{
//pdfDoc = new PdfDocument(reader);
//pdfDoc = new PdfDocument(new PdfReader(pdfFile.FullName));
//Console.WriteLine("Number of Pages: " + pdfDoc.GetNumberOfPages());
//pdfDoc.Close();
}
}
catch(Exception ex)
{
log.Error(ex.Message, ex);
throw new Exception("Invalid PDF File: " + pdfFile.Name);
}
finally
{
if (reader != null)
{
reader.Close();
}
if (pdfDoc != null && !pdfDoc.IsClosed())
{
pdfDoc.Close();
}
try
{
if (testFile.Exists)
{
testFile.Delete();
}
}
catch (Exception ee)
{
Console.WriteLine(ee.Message);
}
}
Looks like an iText bug. If you trace out what gets called by the PdfReader constructor, you see that it creates a FileStream that is conditionally locked. The FileStream gets wrapped in a RandomAccessSource which is then wrapped in a PdfTokenizer in GetOffsetTokeniser. If GetHeaderOffset throws on line 1433, that tok local is never closed.
I'm pretty new to C# and I'm experimenting a lot, I'm trying to make my program a little more user friendly and that is where the problem starts.
At first the location of the excelfile was in a public static string and I had no problems. I've changed it to this:
public string Excellocation()
{
string xlLocation;
if (but_Browse.Text == "Zoek Excel")
{
xlLocation = #"E:\Levi\Documents\Verjaardagen.xlsx";
}
else //Only if I get into this part of my code I get the error
{
xlLocation = but_Browse.Text;
}
return xlLocation;
}
And the button I use so the user can give me a location for the excel file is:
private void but_Browse_Click(object sender, EventArgs e)
{
var FD = new System.Windows.Forms.OpenFileDialog();
if (FD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string fileToOpen = FD.FileName;
System.IO.FileInfo File = new System.IO.FileInfo(FD.FileName);
//OR
System.IO.StreamReader reader = new System.IO.StreamReader(fileToOpen);
//etc
but_Browse.Text = fileToOpen;
this.but_Browse.AutoSize = true;
But_Import.Visible = true;
}
}
Reading the Excel-file is no problem, my program finds it and processes it, if and only if the user changed the location by using the "Browse button" I get a message from Windows that there is already an excel file with that name and if I want to replace it, If I click away that message, my code gives an error on the line that tries to save the excel file
xlWorkbook.Save();
xlWorkbook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
xlWorkbook.Save() gives me this error:
System.Runtime.InteropServices.COMException occurred
HResult=0x800A03EC Message=Verjaardagen.xlsx can not be saved,
because it's read-only.
I have no idea why I don't get an error with the default location while I do get an error if use my button to give me that same location.
Does anyone know what i'm doing wrong?
Thanks in advance
So the problem is that the file is read only when you try to write to it after going through but_Browse_Click? Are you closing the StreamReader? Try using
reader.close();
in but_Browse_Click.
Perhaps a better way would be:
using (StreamReader reader = new StreamReader(fileToOpen))
{
//all code involving the reader in here
}
This automatically closes on completion.
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)
I have a rich text box that is being updated with log information. There is a button to save the log output to a file. When I use the code below to try to save the output to a file, I receive "The process can't access the file because it is being used by another process" exception. I am not sure why I am receiving this exception. It happens on new files that I create in the dialog. It happens on any file I try to save the information to.
private void saveLog_Click(object sender, EventArgs e)
{
OnFileDialogOpen(this, new EventArgs());
// Displays a SaveFileDialog so the user can save the Image
// assigned to Button2.
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Text File|*.txt|Log File|*.log";
saveFileDialog1.Title = "Save Log File";
saveFileDialog1.ShowDialog();
// If the file name is not an empty string open it for saving.
if (saveFileDialog1.FileName != "")
{
// Saves the Image via a FileStream created by the OpenFile method.
System.IO.FileStream fs =
(System.IO.FileStream)saveFileDialog1.OpenFile();
// Saves the Image in the appropriate ImageFormat based upon the
// File type selected in the dialog box.
// NOTE that the FilterIndex property is one-based.
switch (saveFileDialog1.FilterIndex)
{
case 1:
try
{
this.logWindow.SaveFile(saveFileDialog1.FileName, RichTextBoxStreamType.PlainText);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
break;
case 2:
try
{
this.logWindow.SaveFile(saveFileDialog1.FileName, RichTextBoxStreamType.PlainText);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
break;
}
fs.Close();
OnFileDialogClose(this, new EventArgs());
}
}
It seems the same file is opened twice. First you create it using:
System.IO.FileStream fs =
(System.IO.FileStream)saveFileDialog1.OpenFile();
Then you pass the same file name to this.logWindow.SaveFile, which presumably opens the file with the given name and saves data to it.
I guess the first call is unnecessary.