]> source.dussan.org Git - poi.git/commitdiff
[bug-64542] allow file channel closing to be controlled by calling code
authorPJ Fanning <fanningpj@apache.org>
Sat, 9 Oct 2021 13:12:15 +0000 (13:12 +0000)
committerPJ Fanning <fanningpj@apache.org>
Sat, 9 Oct 2021 13:12:15 +0000 (13:12 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894068 13f79535-47bb-0310-9956-ffa450edef68

poi/src/main/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
poi/src/main/java/org/apache/poi/poifs/nio/FileBackedDataSource.java

index ebee94394b1f5f3ef2f041bea773bb7b5bf2d934..1a625f38d0e384bae9e18865cbbfa7eab2e821b3 100644 (file)
@@ -164,7 +164,7 @@ public class POIFSFileSystem extends BlockStore
      */
     public POIFSFileSystem(File file, boolean readOnly)
             throws IOException {
-        this(null, file, readOnly, true);
+        this(null, file, readOnly, true, true);
     }
 
     /**
@@ -198,12 +198,33 @@ public class POIFSFileSystem extends BlockStore
      */
     public POIFSFileSystem(FileChannel channel, boolean readOnly)
             throws IOException {
-        this(channel, null, readOnly, false);
+        this(channel, null, readOnly, false, true);
     }
 
-    @SuppressWarnings("java:S2095")
-    private POIFSFileSystem(FileChannel channel, File srcFile, boolean readOnly, boolean closeChannelOnError)
+    /**
+     * <p>Creates a POIFSFileSystem from an open <tt>FileChannel</tt>. This uses
+     * less memory than creating from an <tt>InputStream</tt>.</p>
+     *
+     * <p>Note that with this constructor, you will need to call {@link #close()}
+     * when you're done to have the underlying resources closed. The <code>closeChannel</code>
+     * parameter controls whether the provided channel is closed.</p>
+     *
+     * @param channel      the FileChannel from which to read or read/write the data
+     * @param readOnly     whether the POIFileSystem will only be used in read-only mode
+     * @param closeChannel whether the provided FileChannel should be closed when
+     *                     {@link #close()} is called, or when this constructor throws
+     *                     an exception
+     * @throws IOException on errors reading, or on invalid data
+     * @since POI 5.1.0
+     */
+    public POIFSFileSystem(FileChannel channel, boolean readOnly, boolean closeChannel)
             throws IOException {
+        this(channel, null, readOnly, closeChannel, closeChannel);
+    }
+
+    @SuppressWarnings("java:S2095")
+    private POIFSFileSystem(FileChannel channel, File srcFile, boolean readOnly, boolean closeChannelOnError,
+                            boolean closeChannelOnClose) throws IOException {
         this(false);
 
         try {
@@ -216,7 +237,7 @@ public class POIFSFileSystem extends BlockStore
                 channel = d.getChannel();
                 _data = d;
             } else {
-                _data = new FileBackedDataSource(channel, readOnly);
+                _data = new FileBackedDataSource(channel, readOnly, closeChannelOnClose);
             }
 
             // Get the header
index e3001f238f34a697a65eeba65655fca973e7b565..31e439fb5dc6f603367f90cfcecb468a92634e6d 100644 (file)
@@ -43,6 +43,7 @@ public class FileBackedDataSource extends DataSource implements Closeable {
     private Long channelSize;
 
     private final boolean writable;
+    private final boolean closeChannelOnClose;
     // remember file base, which needs to be closed too
     private final RandomAccessFile srcFile;
 
@@ -64,19 +65,28 @@ public class FileBackedDataSource extends DataSource implements Closeable {
     }
 
     public FileBackedDataSource(RandomAccessFile srcFile, boolean readOnly) {
-        this(srcFile, srcFile.getChannel(), readOnly);
+        this(srcFile, srcFile.getChannel(), readOnly, false);
     }
 
     public FileBackedDataSource(FileChannel channel, boolean readOnly) {
-        this(null, channel, readOnly);
+        this(channel, readOnly, true);
     }
 
-    private FileBackedDataSource(RandomAccessFile srcFile, FileChannel channel, boolean readOnly) {
+    /**
+     * @since POI 5.1.0
+     */
+    public FileBackedDataSource(FileChannel channel, boolean readOnly, boolean closeChannelOnClose) {
+        this(null, channel, readOnly, closeChannelOnClose);
+    }
+
+    private FileBackedDataSource(RandomAccessFile srcFile, FileChannel channel, boolean readOnly, boolean closeChannelOnClose) {
         this.srcFile = srcFile;
         this.channel = channel;
         this.writable = !readOnly;
+        this.closeChannelOnClose = closeChannelOnClose;
     }
 
+
     public boolean isWriteable() {
         return this.writable;
     }
@@ -170,7 +180,7 @@ public class FileBackedDataSource extends DataSource implements Closeable {
         if (srcFile != null) {
             // see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4796385
             srcFile.close();
-        } else {
+        } else if (closeChannelOnClose) {
             channel.close();
         }
     }