-1

(This is using Unity 2020.1.4f1 with Trilib 2.0.9 Model Loader)

I'm trying to extract the bytes from a zipStream (to load the bytes[] into a Texture2D.LoadImage() in Unity). How do you do this?

Here's what I have tried and the error I am getting:

I'm getting the error: "Cannot access a closed Stream." for Stream zipStream = zipFile.GetInputStream(e) where e is a ZipEntry from a ZipFile (produced by a closed-source sdk)


 Stream zipStream = zipFile.GetInputStream(e); // error occurs here
 
      tex.LoadImage(ReadFully(zipStream));
      tex.Apply();
 

    public static byte[] ReadFully(Stream input)
    {
        byte[] buffer = new byte[16 * 1024];
        using (MemoryStream ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            return ms.ToArray();
        }
    }

and e is extracted within a loop - if that matters

foreach (ZipEntry e in zipFile)
        {
            if (e.IsFile)
            { ... 

ObjectDisposedException: Cannot access a closed Stream.
System.IO.MemoryStream.Seek (System.Int64 offset, System.IO.SeekOrigin loc) (at <fb001e01371b4adca20013e0ac763896>:0)
ICSharpCode.SharpZipLib.Zip.ZipFile.TestLocalHeader (ICSharpCode.SharpZipLib.Zip.ZipEntry entry, ICSharpCode.SharpZipLib.Zip.ZipFile+HeaderTest tests) (at <1a5a474a643a454ba874ca384c215100>:0)
ICSharpCode.SharpZipLib.Zip.ZipFile.LocateEntry (ICSharpCode.SharpZipLib.Zip.ZipEntry entry) (at <1a5a474a643a454ba874ca384c215100>:0)
ICSharpCode.SharpZipLib.Zip.ZipFile.GetInputStrea

ina
  • 19,167
  • 39
  • 122
  • 201
  • I am not familiar with Unity stuff, but still I would want to see the full method that you are using so I can see how the stream is being fetched and passed. – Jamshaid K. Nov 03 '20 at 20:40
  • All I have is the `ZipFile` as an object - I am able to iterate it to get its `ZipEntry`, and `e.Name` seems to work... maybe the question is how do you open the `ZipFile` for extracting individual `ZipEntry` streams? – ina Nov 03 '20 at 20:43
  • So, do you want to open a zipped file and read the individual file from it, right? – Jamshaid K. Nov 03 '20 at 20:47
  • No... the ZipFile is already passed in code as some sort of ZipFile object – ina Nov 03 '20 at 20:53
  • I have a zipped file loaded in a `ZipFile` object. I am getting back its entries and the stream object from it. See this sample, https://prnt.sc/vcv2z0 – Jamshaid K. Nov 03 '20 at 21:02
  • I think the issue might be that the SDK is producing a `ZipFile` and closing it before I can access it. How do re-open it or how you create a new `ZipFile` from a closed `ZipFile`? – ina Nov 03 '20 at 21:06
  • It depends, we are not able to see the complete code as we do not know about what is causing it to close the stream, or maybe it is you unknowingly closing the stream. – Jamshaid K. Nov 03 '20 at 21:08
  • I have not called .Close() on it. SO I get the ZipFile by calling sdkinstance.ZipFile... I can loop thru to get the file names, but when I try getting the streams, the error above occurs – ina Nov 03 '20 at 21:10
  • in your snippet, the error also occurs in the same using getInputStream line – ina Nov 03 '20 at 21:11
  • While I am able to correctly load the stream, Can you share complete method of yours so I can reproduce the error as I can't do it because it works from my side. See: https://prnt.sc/vcvcjq – Jamshaid K. Nov 03 '20 at 21:16
  • Instead of opening from file system, can you try creating a new ZipFile using an existing ZipFile object? – ina Nov 03 '20 at 21:18
  • my issue is line 92 in your snippet. it could be due to "System.ObjectDisposedException The ZipFile has already been closed" – ina Nov 03 '20 at 21:18
  • 1
    I am not sure about how are you going to create a `ZipFile` from the `ZipFile` object. It doesn't directly accept a zipfile object in the constructor to clone it. – Jamshaid K. Nov 03 '20 at 21:23
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/224065/discussion-between-jamshaid-kamran-and-ina). – Jamshaid K. Nov 03 '20 at 21:24
  • Hi, the approach of not using TriLib's downloader feature seems to work. Manually extract zip, use local model loader etc. Thanks you for this idea! – ina Nov 03 '20 at 23:19

2 Answers2

3

So, we discussed the issue in chat and the problem with ZipFile was, it contained no File Name and no Stream in it. Which technically means, we cannot get stream of the individual files in the ZipFile object.

Scenario: They were using TriLib and passing the URL of the zip file that was available on a server. What TriLib did was, it fetched the file and information, parsed it in an object and returned the object into a method upon completion.

The Problem: ZipFile object contained no information regarding the Individual Files and their Stream neither it had a name, so the Name property was coming null. Which means, we couldn't perform any operation on the ZipFile object.

Solution: We made a custom downloader and downloaded the file onto disk, then passed the downloaded file to the ZipFile constructor, by using this approach, we had all the information inside of a zip file.

Jamshaid K.
  • 3,555
  • 1
  • 27
  • 42
  • Thanks for the debug! Being a self-taught programmer, it really helped to see how someone else would debug a situation. – ina Nov 04 '20 at 02:04
1

I believe the problem is that the input streams of each zip entry are connected to the input stream of the whole file. Closing that stream causes the file stream to close. Remove the using around the entry stream, and I believe your code should work.

ILMTitan
  • 10,751
  • 3
  • 30
  • 46