1
votes

Our app is running in Docker and we have limited memory available in each process. We work with and zip large files so it is customary to use FileStreams as temporary streams with the FileOptions.DeleteOnClose option.

When we create a zip file we create a temporary file stream, use ZipArchive to write to the stream, dispose the ZipArchive, rewind the stream, and copy the stream's contents to some persistent store like Mongo GridFS. The problem we are running into is that the zip file in the persistent store is an invalid zip file.

To isolate the issue we created a persistent 'temporary' file stream and checked it for validity after we dispose the ZipArchive and after we dispose the file stream. What we are seeing is that the filestream after the ZipArchive Dispose() is an INVALID zip file, but after the filestream Dispose() it is a VALID stream. After the filestream is disposed, the length on disk DOES NOT MATCH the length before it was disposed. Why is the file on disk not a valid zip file until the filestream is disposed?

    [Test]
    public async Task ZipFile2()
    {
        string zipPath = Path.Combine(Path.GetTempPath(), "test.zip");
        long streamLengthBeforeClose;

        using (var sourceFile = new FileStream("../../../../Foundations.Blob.UnitTests/TestData/test-file.txt", FileMode.Open))
        using (var zipStream = new FileStream(zipPath, FileMode.Create))
        {
            using var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true);
            {
                var entry = archive.CreateEntry("test-file.txt");
                using (var entryStream = entry.Open())
                {
                    // copy from the blob to the zip entry
                    await sourceFile.CopyToAsync(entryStream, CancellationToken.None);
                }
            }
            zipStream.Flush();

            // at this point the zipStream IS NOT A VALID ZIP FILE

            streamLengthBeforeClose = zipStream.Length;
        }

        // at this point the zipStream IS A VALID ZIP FILE

        var fi = new FileInfo(zipPath);

        // These do not match
        Assert.AreEqual(streamLengthBeforeClose, fi.Length);
    }

Note: we do not want to use persistent temporary file streams wrapped with a try/finally with a delete. Nor are memory streams viable solutions.

1

1 Answers

0
votes

Change line instantiating archive:

using var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true);

To:

using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))

Otherwise you have you streams disposal mixed up which leads to described behaviour.