View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.compressors.xz;
20  
21  import java.io.IOException;
22  import java.io.OutputStream;
23  
24  import org.apache.commons.compress.compressors.CompressorOutputStream;
25  import org.apache.commons.io.build.AbstractStreamBuilder;
26  import org.tukaani.xz.LZMA2Options;
27  import org.tukaani.xz.XZOutputStream;
28  
29  // @formatter:off
30  /**
31   * Compresses an output stream using the XZ and LZMA2 compression options.
32   * <p>
33   * For example:
34   * </p>
35   * <pre>{@code
36   * XZCompressorOutputStream s = XZCompressorOutputStream.builder()
37   *   .setPath(path)
38   *   .setLzma2Options(new LZMA2Options(...))
39   *   .get();
40   * }
41   * </pre>
42   *
43   * <h2>Calling flush</h2>
44   * <p>
45   * Calling {@link #flush()} flushes the encoder and calls {@code outputStream.flush()}. All buffered pending data will then be decompressible from the output
46   * stream. Calling this function very often may increase the compressed file size a lot.
47   * </p>
48   *
49   * @since 1.4
50   */
51  // @formatter:on
52  public class XZCompressorOutputStream extends CompressorOutputStream<XZOutputStream> {
53  
54      // @formatter:off
55      /**
56       * Builds a new {@link XZCompressorOutputStream}.
57       *
58       * <p>
59       * For example:
60       * </p>
61       * <pre>{@code
62       * XZCompressorOutputStream s = XZCompressorOutputStream.builder()
63       *   .setPath(path)
64       *   .setLzma2Options(new LZMA2Options(...))
65       *   .get();
66       * }
67       * </pre>
68       *
69       * @see #get()
70       * @since 1.28.0
71       */
72      // @formatter:on
73      public static class Builder extends AbstractStreamBuilder<XZCompressorOutputStream, Builder> {
74  
75          private LZMA2Options lzma2Options = new LZMA2Options();
76  
77          /**
78           * Constructs a new builder of {@link XZCompressorOutputStream}.
79           */
80          public Builder() {
81              // empty
82          }
83  
84          @Override
85          public XZCompressorOutputStream get() throws IOException {
86              return new XZCompressorOutputStream(this);
87          }
88  
89          /**
90           * Sets LZMA options.
91           * <p>
92           * Passing {@code null} resets to the default value {@link LZMA2Options#LZMA2Options()}.
93           * </p>
94           *
95           * @param lzma2Options LZMA options.
96           * @return this instance.
97           */
98          public Builder setLzma2Options(final LZMA2Options lzma2Options) {
99              this.lzma2Options = lzma2Options != null ? lzma2Options : new LZMA2Options();
100             return this;
101         }
102 
103     }
104 
105     /**
106      * Constructs a new builder of {@link XZCompressorOutputStream}.
107      *
108      * @return a new builder of {@link XZCompressorOutputStream}.
109      * @since 1.28.0
110      */
111     public static Builder builder() {
112         return new Builder();
113     }
114 
115     @SuppressWarnings("resource") // Caller closes
116     private XZCompressorOutputStream(final Builder builder) throws IOException {
117         super(new XZOutputStream(builder.getOutputStream(), builder.lzma2Options));
118         }
119 
120     /**
121      * Creates a new XZ compressor using the default LZMA2 options. This is equivalent to {@code XZCompressorOutputStream(outputStream, 6)}.
122      *
123      * @param outputStream the stream to wrap
124      * @throws IOException on error
125      */
126     public XZCompressorOutputStream(final OutputStream outputStream) throws IOException {
127         this(builder().setOutputStream(outputStream));
128     }
129 
130     /**
131      * Creates a new XZ compressor using the specified LZMA2 preset level.
132      * <p>
133      * The presets 0-3 are fast presets with medium compression. The presets 4-6 are fairly slow presets with high compression. The default preset is 6.
134      * </p>
135      * <p>
136      * The presets 7-9 are like the preset 6 but use bigger dictionaries and have higher compressor and decompressor memory requirements. Unless the
137      * uncompressed size of the file exceeds 8&nbsp;MiB, 16&nbsp;MiB, or 32&nbsp;MiB, it is waste of memory to use the presets 7, 8, or 9, respectively.
138      * </p>
139      *
140      * @param outputStream the stream to wrap
141      * @param preset       the preset
142      * @throws IOException on error
143      * @deprecated Use {@link #builder()}.
144      */
145     @Deprecated
146     @SuppressWarnings("resource") // Caller closes
147     public XZCompressorOutputStream(final OutputStream outputStream, final int preset) throws IOException {
148         super(new XZOutputStream(outputStream, new LZMA2Options(preset)));
149     }
150 
151     /**
152      * Finishes compression without closing the underlying stream. No more data can be written to this stream after finishing.
153      *
154      * @throws IOException on error
155      */
156     @Override
157     @SuppressWarnings("resource") // instance variable access
158     public void finish() throws IOException {
159         out().finish();
160     }
161 
162     @Override
163     public void write(final byte[] buf, final int off, final int len) throws IOException {
164         out.write(buf, off, len);
165     }
166 
167 }