Cannot access the file because it is being used by another process - c#

My web method creates a pdf file in my %temp% folder and that works. I then want to add some custom fields (meta) to that file using the code below.
The class PdfStamper generates an IOException, whether I use its .Close() method or the using block just ends. The process that is still holding on to the file handle is the webdev web server itself (I'm debugging in VS2010 SP1).
private string AddCustomMetaData(string guid, int companyID, string filePath)
{
try
{
PdfReader reader = new PdfReader(filePath);
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
PdfStamper st = new PdfStamper(reader, fs);
Dictionary<string, string> info = reader.Info;
info.Add("Guid", guid);
info.Add("CompanyID", companyID.ToString());
st.MoreInfo = info;
st.Close();
}
reader.Close();
return guid;
}
catch (Exception e)
{
return e.Message;
}
}
No matter what I try, it keeps throwing the exception at st.Close();, to be more precise:
The process cannot access the file 'C:\Users[my
username]\AppData\Local\Temp\53b96eaf-74a6-49d7-a715-6c2e866a63c3.pdf'
because it is being used by another process.
Either I'm overlooking something obvious or there's a problem with the PdfStamper class I'm as of yet unaware of. Versions of itextsharp used are 5.3.3.0 and 5.4.0.0, the issue is the same.
Any insight would be greatly appreciated.
EDIT: I'm currently "coding around" the issue, but I haven't found any solution.

Your problem is that you are writing to a file while you are also reading from it. Unlike some file types (JPG, PNG, etc) that "load" all of the data into memory, iTextSharp reads the data as a stream. You either need to use two files and swap them at the end or you can force iTextSharp to "load" the first file by binding your PdfReader to a byte array of the file.
PdfReader reader = new PdfReader(System.IO.File.ReadAllBytes(filePath));

I suggest you to use the FileShare enumerator when you open the file, so Try to open a file with None sharing
File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None);

Try to .Dispose() your PDF reader (or whatever you use for creating it) when you save the file for the first time

Try this solution if you think its feasible for you - Once the webmethod creates file in Temp folder, you need to copy the file and paste it into other location or same location with different name and pass newly copied file path to your PDF reader.

Related

Creating a new Document with a FileStream with Aspose.Pdf

I'm trying to create a new Aspose.Pdf.Document using a FileStream to a new File, but it always throws an "Incorrect File Header" Exception. I need to work with the FileStream so that I can incrementally save the Document when merging other Pdf documents without keeping all of the Streams in scope.
According to the documentation, the following is the code to create a Document with a FileStream (I changed FileMode.Open to FileMode.OpenOrCreate since I don't have an existing Pdf file and want to start with a blank Document).
await using var fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
var document = new Document(fileStream);
This code throws an "Incorrect File Header" Exception unless the FileStream points to an existing valid Pdf file.
The following code works, but it's kind of silly to create and dispose a Document just so that we can work with the Document through the FileStream.
var fileName = Path.GetTempFileName();
var doc = new Document();
doc.Save(fileName);
doc.Dispose();
await using var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
var document = new Document(fileStream);
I have to be missing something painfully obvious, because this is an incredibly simple use case and I don't see anything about it when searching online.
You cannot initialize the Document object with an empty Stream or invalid PDF file. File or Stream should be a valid PDF document. In order to use the incremental saving approach, you can initialize the FileStream with a new file and keep saving the Document into it. For example, please check the below sample code snippet:
using var fileStream = new FileStream(dataDir + "output.pdf", FileMode.OpenOrCreate, FileAccess.ReadWrite);
{
var document = new Document();
document.Pages.Add();
document.Save(fileStream);
document.Pages.Add();
document.Save(fileStream);
}
Please note that the FileStream needs to remain open during the whole process of PDF generation. Along with that, you can also use Document.Save(); method (without any constructor) to implement incremental saving.
We believe that you have also posted a similar inquiry in Aspose.PDF official support forum and we have responded to you there as well. You can please follow up on it there and carry on the discussion in case you need more information.
This is Asad Ali and I work as Developer Evangelist at Aspose.

Adobe Reader could not open 'StreamTest5.pdf' because it is either not a supported file or file has been damaged error

I am trying to create a pdf file using file stream and while the file is being created in the specified folder of the path, when I try to open the file Adobe Reader is throwing the error that I mentioned above in the title. I am not sure what I am doing wrong but I would greatly appreciate it if someone could look into it and help me out. Thank you!. Here is my code for the filestream:
System.IO.FileStream wFile;
byte[] byteData = null;
byteData = Encoding.ASCII.GetBytes("FileStream Test");
string filePath = $"{_ApplicationPath}PrintedResults\\StreamTest5.pdf";
wFile = new FileStream(filePath, FileMode.Create);
wFile.Write(byteData, 0, byteData.Length);
wFile.Close();
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
Console.WriteLine("This is a test stream file");
}
System.Diagnostics.Process.Start(filePath);
You are writing a text file with the contents "FileStream Test" but naming it with a file extension of ".PDF". This is not a PDF file. It is a text file with a misleading name. Adobe Reader is correctly reporting that it is not a valid PDF.
This is not an answer but I don't have enough reputation to add it as a comment:
You might want to look to 3rd party library offered by http://www.dynamicpdf.com/
Their free evaluation version is quite capable and it is not time limited as they say on their website. With a little more effort you can create quite complicated PDFs with only the evaluation version!

C# iTextSharp: The process cannot access the file because it is being used by another process

I'm generating a pdf file from a template with iTextSharp, filling each field in this code portion:
PdfReader pdfReader = new PdfReader(templatePath);
try
{
using (FileStream newFileStream = new FileStream(newFilePath, FileMode.Create))
{
using (PdfStamper stamper = new PdfStamper(pdfReader, newFileStream))
{
// fill each field
AcroFields pdfFormFields = stamper.AcroFields;
foreach (KeyValuePair<string, string> entry in content)
{
if (!String.IsNullOrEmpty(entry.Value))
pdfFormFields.SetField(entry.Key, entry.Value);
}
//The below will make sure the fields are not editable in
//the output PDF.
stamper.FormFlattening = true;
stamper.Close();
}
}
}
finally
{
pdfReader.Close();
}
Everything goes fine, file looks ok, but when i try to reopen the file to merge it with some other files I've generated in a unique document i get this error:
2015-11-23 09:46:54,651||ERROR|UrbeWeb|System.IO.IOException: The process cannot access the file 'D:\Sviluppo\communitygov\MaxiAnagrafeImmobiliare\MaxiAnagrafeImmobiliare\cache\IMU\E124\admin\Stampe\Provvedimento_00223850306_2015_11_23_094654.pdf' because it is being used by another process.
Error occurs at this point
foreach (Documento item in docs)
{
string fileName = item.FilePath;
pdfReader = new PdfReader(fileName); // IOException
// some other operations ...
}
Edit: Using Process monitor as suggested I can see there is no close CloseFile operation as I would expect. Can this be the source of the issue?
I've been stuck on this for hours any help is really really appreciated.
Had the same issue with me. This helped a lot.
"You're problem is that you are writing to a file while you are also reading from it. Unlike some file types (JPG, PNG, etc) that "load" all of the data into memory, iTextSharp reads the data as a stream. You either need to use two files and swap them at the end or you can force iTextSharp to "load" the first file by binding your PdfReader to a byte array of the file."
PdfReader reader = new PdfReader(System.IO.File.ReadAllBytes(filePath));
Ref: Cris Haas answer to Cannot access the file because it is being used by another process
I had a similar problem with opening pdf files (for read only) with iTextSharp PdfReader. The first file gave no problem, the second one gave that exception (can not access the file, etc.).
After hours and googling and searching for complicate solutions and twisting my brain, only the simple following code resolved it fully:
iTextSharp_pdf.PdfReader pdfReader = null;
pdfReader = new iTextSharp_pdf.PdfReader(fileName);

How to open a file in memory?

I have see this term branded around but I don't really understand how you open a file in memory.
I have the files written to disk in a temp location but this needs cleaning when a certain form closes and I can't do it when it's open. It's a must that this folder gets emptied. I was wondering if I opened files in memory instead whether it would make a difference?
MemoryStream inMemoryCopy = new MemoryStream();
using (FileStream fs = File.OpenRead(path))
{
fs.CopyTo(inMemoryCopy);
}
// Now you can delete the file at 'path' and still have an in memory copy
I think you want to work with Memory Mapped files added recently to .NET 4.
http://blogs.msdn.com/b/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx
Memory Mapped Files .NET
I think it means to read the content of that file into memory as a whole and then close the connection to the file. Assuming it's a file that's not too big you could just read it into a byte[]:
byte[] fileContent = File.ReadAllBytes(fileName);
If it's a text file read it into a string using
string fileContent = File.ReadAllText(fileName);
Once you've done that use a StreamReader to read it later as you would a file on disk.
You can use DeleteOnClose parameter of FileStream constructor:
FileStream fs = new FileStream("<Path Here>", FileMode.Create,
FileAccess.ReadWrite, FileShare.None, 1024, FileOptions.DeleteOnClose);
and the file will be deleted when closed.

How to read a file which is currently used, like Windows does when copying it?

One of my applications is intended to read (and only read) files which may be in use.
But, when reading a file which is already opened in, for example, Microsoft Word, this application throws a System.IO.IOException:
The process cannot access the file '<filename here>' because it is being used by another process.
The code used to read the file is:
using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
{
// Do stuff here.
}
Of course, since the file is already used, this exception is expected.
Now, if I ask the operating system to copy the file to a new location, then to read it, it works:
string tempFileName = Path.GetTempFileName();
File.Copy(fileName, tempFileName, true);
// ↓ We read the newly created file.
using (Stream stream = new FileStream(tempFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
{
// Do stuff here.
}
What is the magic of File.Copy which allows to read the file already used by an application, and especially how to use this magic to read the file without making a temporary copy?
Nice question there. Have a look at this, it seems to suggest using FileShare.ReadWrite only is the key, it's worth a shot.
http://www.geekzilla.co.uk/viewD21B312F-242A-4038-9E9B-AE6AAB53DAE0.htm
try removing FileShare.ReadWrite | FileShare.Delete from the FileStream constructor, or at least FileShare.Delete.

Categories

Resources