Getting System.IO.IOException during Workbook.Save(<stream>- FileFormatType.AsposePdf) method

Hi,

Briefly, I have a template .XLS file that contains (among other things) an image (the company logo). I create a Workbook and open the template in this. I then create other workbooks and, for each, copy the template worksheet from the template workbook into the new workbook then save these to a stream in the AsposePdf format, followed by the creation of the PDF, the binding of the XML, and saving the result.

For the first one or two copies this works fine, but after then I'll get a System.IO.IOException during the save, complaining that:

The process cannot access the file 'C:\Documents and Settings\...\Local Settings\Temp\tmpFile.tmp_img0.jpg' because it is being
used by another process.

If I repeat the process on exactly the same data set, it doesn't always happen on the same copy (e.g. it might happen on the third iteration, or perhaps the fourth). This would seem to suggest that some resource is not being appropriately released.

Right now, the program is operating single-threaded yet I'm getting this problem...what happens when I have it go multi-threaded (so that I'd be using my template to create multiple workbook copies at one time)? Will I find that this templating paradigm I'm using does not work multi-threaded?

The relevant stack trace:

System.IO.IOException: The process cannot access the file 'C:\Documents and Settings\clotridge\Local Settings\Temp\tmpFile.tmp_img0.jpg' because it is being
used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOption
s options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode)
at Aspose.Cells.Pdf.?.?()
at Aspose.Cells.Pdf.?.?()
at Aspose.Cells.Pdf.?.?(Stream ?)
at Aspose.Cells.Workbook.Save(Stream stream, FileFormatType fileFormatType)

Thanks,

Charlie Lotridge

Hi,

Could you check if you are running the application in full trust mode with all the accessibility rights and don't have any security issue. And could you separate Aspose.Cells related code only and process the code repeatedly if it works fine and does not produce the error.

e.g..,

Workbook wb = new Workbook();

wb.Open("d:\\test\\mybook.xls");

.

.

wb.Save(stream,FileFormatType.AsposePdf);

If the problem still persists, could you create a sample test project using Aspose.Cells and Aspose.Pdf (lastest versions of both components), zip the project and post it here. We will check it soon.

Thank you.

Hi,

I’ve created a workaround to this problem, but it really should be fixed.

No, the problem has nothing to do with security or permissions. Here’s what’s happening…

Whenever the Workbook.Save(stream, FileFormatType.AsposePdf) is used, if the workbook contains any image files it copies these into the TEMP directory, but using a fixed naming scheme that seems to be dependant upon the type of stream. For streams associated with files, the names of these image files includes the file name. But for a MemoryStream, they look something “tmpFile.tmp_img0.jpg”. This file then must live until it is subsequently bound to an Aspose.Pdf then that object is saved to a file.

So, for example, consider the following and assume that the workbook contains some JPG image:

//***********************************************************************************************

private void CopyToPDF(Workbook workbook, Stream outputStream) {

//

// Create a temporary memory stream

using (MemoryStream memoryStream = new MemoryStream()) {

//

// Save the XLS into the memory stream as PDF XML

workbook.Save(memoryStream, FileFormatType.AsposePdf); // THIS CREATES THE TEMPORARY FILE

//

// Create a PDF

Aspose.Pdf.Pdf pdf = new Aspose.Pdf.Pdf();

//

// Bind our document

pdf.BindXML(memoryStream, null); // THIS OPENS AND LOCKS THE TEMPORARY FILE

//

// Instruct it to delete images – THIS SHOULD INSTRUCT THE Pdf OBJECT TO DELETE THE FILE BUT IT DOESN’T WORK

pdf.IsImagesInXmlDeleteNeeded = true;

//

// Save the result to the output stream

pdf.Save(outputStream);

}

//

// Force garbage collection – THIS SHOULD, BUT DOES NOT RELEASE THE FILE SINCE THE Pdf OBJECT IS OUT OF SCOPE AND SHOULD BE COLLECTED

GC.Collect();

GC.WaitForPendingFinalizers();

}

The real problem is that the temporary files created should be uniquely named. My program will have multiple threads all potentially doing exactly this same thing, and without making this code a critical region (which I don’t want to do) the threads would each be stomping on each other’s temporary files (not to mention the locked file issue).

Further, the Pdf object should implement IDisposable, and should release its resources upon Dispose(). I didn’t spend too much time on it, but even after the forced garbage collection the temporary image file is not released until some arbitrary time later. Not sure why.

Here’s a workaround. This routine goes through the intermediary XML and renames all of these temporary files to new unique names, and returns a new MemoryStream which can then be bound to a Pdf object. I’ve only tried it in my own limited scope, so anyone using this should carefully verify it works for them:

//***********************************************************************************************

static MemoryStream ChangeTemporaryImageFilenames(Stream inputStream) {

//

// Create an XmlDocument and load the contents of the stream

XmlDocument xmlDocument = new XmlDocument();

xmlDocument.Load(inputStream);

//

// Create an XmlNamespaceManager to resolve the default namespace.

XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDocument.NameTable);

nsmgr.AddNamespace("Aspose", "Aspose.Pdf");

//

// Loop through all File attributes of image nodes at the proper depth

int counter = 0;

foreach (XmlNode node in xmlDocument.SelectNodes(@"/Aspose:Pdf/Section/Table/Row/Cell/Image/@File", nsmgr)) {

//

// Get a FileInfo on the image file

FileInfo fileInfo = new FileInfo(node.InnerText);

//

// Create a new unique name

node.InnerText = String.Format(@"{0}\{1}-{2}-{3}{4}", fileInfo.DirectoryName, DateTime.Now.Ticks,

System.Threading.Thread.CurrentThread.ManagedThreadId, counter++, fileInfo.Extension);

//

// Move the file to the new name

fileInfo.MoveTo(node.InnerText);

}

//

// Create a new stream for the result

MemoryStream outputStream = new MemoryStream();

//

// Create an XmlTextWriter on the stream

XmlTextWriter textWriter = new XmlTextWriter(outputStream, null);

textWriter.Formatting = Formatting.Indented;

//

// Write the file out

xmlDocument.WriteTo(textWriter);

//

// Return the new stream

return outputStream;

}

Hi,

Could you remove all codes about Aspose.Pdf ? It will help us whether there is the problem with Aspose.Cells.

And please try this fix.

In this fix,we use Cell.GetStyle and SetStyle method replace the property of Cell.Style. The two methods will save more memory usage than cell.Style property.

If you want to set style of the cell, please change your codes as :

//Getting the style of the cell.

Style style = cell.GetStyle();

//Setting the property of the style.

.......

//Setting the style of the cell

cell.SetStyle(style);

Hi Warren,

It looks like your reply should have been for some other thread.

Thanks,

Charlie Lotridge

Hi,

Please try that fix. If you apply that fix ,you have to change your codes with the info.