1

I have a helper class with a static method that returns a stream:

public static InputStream getDocument(File file) throws IOException {
    ZipFile zipFile = new ZipFile(file);
    return zipFile.getInputStream(zipFile.getEntry("entry"));
}

Another class accesses that method and uses that returned stream:

InputStream is = MyClass.getDocument(new File(str));

My code works.


However, according to the Java Documentation, I should close my resource:

A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement.

But, when I implement try-with-resources:

public static InputStream getDocument(File file) throws IOException {
    try (ZipFile zipFile = new ZipFile(file);) {
        return zipFile.getInputStream(zipFile.getEntry("entry"));
    }
}

or try-finally:

public static InputStream getDocument(File file) throws IOException {
    InputStream is = null;
    try {
        ZipFile zipFile = new ZipFile(docx);
        is = zipFile.getInputStream(zipFile.getEntry("entry"));
        return is;
    } finally {
        is.close();
    }
}

I get an exception:

java.io.IOException: Stream closed

How to make sure, that resource will be closed, after its use?

Evgenij Reznik
  • 17,916
  • 39
  • 104
  • 181
  • 4
    the caller is responsible to close the resource – fantaghirocco Dec 17 '20 at 15:35
  • @tkruse How is that a duplicate of this question? – Mark Rotteveel Feb 20 '21 at 08:56
  • try with resources adds an implicit finally block, in which it closes the resource. Therefore in both cases, the resource (stream) is closed at the end of the code block. So we have no other options but to differ closing the resource at the method calling site. – Mr.Q Jan 07 '22 at 19:10
  • Related https://stackoverflow.com/questions/3991577/closing-java-inputstreams, https://stackoverflow.com/questions/34980241/why-closing-an-input-stream-closes-the-associated-file-descriptor-as-well-even, https://stackoverflow.com/questions/24274432/does-a-zipentry-persist-after-a-zipfile-is-closed – tkruse Jan 09 '22 at 02:09

2 Answers2

3

Usually the caller is responsible to close/release the resources.
You can use the try-with-resource or the try-finally construct outside the method as follows:

try (InputStream is = getDocument(aFile) {
    //… do your stuff
}

If I can give you an advice, write it in the method documentation:

/**
  * The caller is required to close the returned {@link InputStream}
  */
public static InputStream getDocument(File file) throws IOException
fantaghirocco
  • 4,761
  • 6
  • 38
  • 48
0

try-with-resources does implicitly the same as your second approach with finally. There is no way to close the zipFile but return an inputStream based on this zipFile.

Generally it would be better to avoid this helper method and use a single try-with-resourrces with multiple resources:

try (
   ZipFile zipFile = new ZipFile(file);
   inputStream inputStream = zipFile.getInputStream(zipFile.getEntry("entry"));
) {
    // Do stuff
} // Both zipFile and inputStream closed here implicitly

If you need to create such a method, you can however make sure that when the stream is closed, the zipFile object also gets closed.

From a related question Does a ZipEntry persist after a ZipFile is closed?

zipFile = new ZipFile(file);
InputStream zipInputStream = ...
return new InputStream() {
    @Override
    public int read() throws IOException {
        return zipInputStream.read();
    }
    @Override
    public void close() throws IOException {
        // Better add try/catch around each close()
        zipInputStream.close();
        zipFile.close();
    }
}

That way, when the calling method closes the stream it receives, the zip file would also be closed.

tkruse
  • 10,222
  • 7
  • 53
  • 80
  • the only thing common between these two questions is the word "Stream" – Mr.Q Jan 07 '22 at 19:21
  • No there is a subtle difference, This question is about the returned stream being closed prematurely but in the question you mentioned. It is about making sure to close the resources which are used in creating a Stream (of Strings). – Mr.Q Jan 08 '22 at 06:27
  • I care cause you voted to close the question and also provided an answer that does not fully address the question. – Mr.Q Jan 08 '22 at 14:27
  • I have completely changed my answer and turned it into community wiki. Feel free to use it, though accepted answer might get more views. – tkruse Jan 09 '22 at 02:43