UnsynchronizedReader.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */

  17. package org.apache.commons.io.input;

  18. import static org.apache.commons.io.IOUtils.EOF;

  19. import java.io.IOException;
  20. import java.io.Reader;

  21. import org.apache.commons.io.IOUtils;

  22. /**
  23.  * A {@link Reader} without any of the superclass' synchronization.
  24.  *
  25.  * @since 2.17.0
  26.  */
  27. public abstract class UnsynchronizedReader extends Reader {

  28.     /**
  29.      * The maximum skip-buffer size.
  30.      */
  31.     private static final int MAX_SKIP_BUFFER_SIZE = IOUtils.DEFAULT_BUFFER_SIZE;

  32.     /**
  33.      * Whether {@link #close()} completed successfully.
  34.      */
  35.     private boolean closed;

  36.     /**
  37.      * The skip buffer, defaults to null until allocated in {@link UnsynchronizedReader#skip(long)}.
  38.      */
  39.     private char skipBuffer[];

  40.     /**
  41.      * Constructs a new instance.
  42.      */
  43.     public UnsynchronizedReader() {
  44.         // empty
  45.     }

  46.     /**
  47.      * Checks if this instance is closed and throws an IOException if so.
  48.      *
  49.      * @throws IOException if this instance is closed.
  50.      */
  51.     void checkOpen() throws IOException {
  52.         Input.checkOpen(!isClosed());
  53.     }

  54.     @Override
  55.     public void close() throws IOException {
  56.         closed = true;
  57.     }

  58.     /**
  59.      * Tests whether this instance is closed; if {@link #close()} completed successfully.
  60.      *
  61.      * @return whether this instance is closed.
  62.      */
  63.     public boolean isClosed() {
  64.         return closed;
  65.     }

  66.     /**
  67.      * Sets whether this instance is closed.
  68.      *
  69.      * @param closed whether this instance is closed.
  70.      */
  71.     public void setClosed(final boolean closed) {
  72.         this.closed = closed;
  73.     }

  74.     /**
  75.      * Skips characters by reading from this instance.
  76.      *
  77.      * This method will <em>block</em> until:
  78.      * <ul>
  79.      * <li>some characters are available,</li>
  80.      * <li>an I/O error occurs, or</li>
  81.      * <li>the end of the stream is reached.</li>
  82.      * </ul>
  83.      *
  84.      * @param n The number of characters to skip.
  85.      * @return The number of characters actually skipped.
  86.      * @throws IllegalArgumentException If {@code n} is negative.
  87.      * @throws IOException              If an I/O error occurs.
  88.      */
  89.     @Override
  90.     public long skip(final long n) throws IOException {
  91.         if (n < 0L) {
  92.             throw new IllegalArgumentException("skip value < 0");
  93.         }
  94.         final int bufSize = (int) Math.min(n, MAX_SKIP_BUFFER_SIZE);
  95.         if (skipBuffer == null || skipBuffer.length < bufSize) {
  96.             skipBuffer = new char[bufSize];
  97.         }
  98.         long remaining = n;
  99.         while (remaining > 0) {
  100.             final int countOrEof = read(skipBuffer, 0, (int) Math.min(remaining, bufSize));
  101.             if (countOrEof == EOF) {
  102.                 break;
  103.             }
  104.             remaining -= countOrEof;
  105.         }
  106.         return n - remaining;
  107.     }
  108. }