mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 02:48:14 -05:00
Update #0 - First Release
This commit is contained in:
128
sources/main/java/com/google/common/io/AppendableWriter.java
Normal file
128
sources/main/java/com/google/common/io/AppendableWriter.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.Flushable;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Writer that places all output on an {@link Appendable} target. If the target
|
||||
* is {@link Flushable} or {@link Closeable}, flush()es and close()s will also
|
||||
* be delegated to the target.
|
||||
*
|
||||
* @author Alan Green
|
||||
* @author Sebastian Kanthak
|
||||
* @since 1.0
|
||||
*/
|
||||
class AppendableWriter extends Writer {
|
||||
private final Appendable target;
|
||||
private boolean closed;
|
||||
|
||||
/**
|
||||
* Creates a new writer that appends everything it writes to {@code target}.
|
||||
*
|
||||
* @param target target to which to append output
|
||||
*/
|
||||
AppendableWriter(Appendable target) {
|
||||
this.target = checkNotNull(target);
|
||||
}
|
||||
|
||||
/*
|
||||
* Abstract methods from Writer
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void write(char cbuf[], int off, int len) throws IOException {
|
||||
checkNotClosed();
|
||||
// It turns out that creating a new String is usually as fast, or faster
|
||||
// than wrapping cbuf in a light-weight CharSequence.
|
||||
target.append(new String(cbuf, off, len));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
checkNotClosed();
|
||||
if (target instanceof Flushable) {
|
||||
((Flushable) target).flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.closed = true;
|
||||
if (target instanceof Closeable) {
|
||||
((Closeable) target).close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override a few functions for performance reasons to avoid creating
|
||||
* unnecessary strings.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void write(int c) throws IOException {
|
||||
checkNotClosed();
|
||||
target.append((char) c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@Nullable String str) throws IOException {
|
||||
checkNotClosed();
|
||||
target.append(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@Nullable String str, int off, int len) throws IOException {
|
||||
checkNotClosed();
|
||||
// tricky: append takes start, end pair...
|
||||
target.append(str, off, off + len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer append(char c) throws IOException {
|
||||
checkNotClosed();
|
||||
target.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer append(@Nullable CharSequence charSeq) throws IOException {
|
||||
checkNotClosed();
|
||||
target.append(charSeq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer append(@Nullable CharSequence charSeq, int start, int end) throws IOException {
|
||||
checkNotClosed();
|
||||
target.append(charSeq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void checkNotClosed() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Cannot write to a closed writer.");
|
||||
}
|
||||
}
|
||||
}
|
925
sources/main/java/com/google/common/io/BaseEncoding.java
Normal file
925
sources/main/java/com/google/common/io/BaseEncoding.java
Normal file
@ -0,0 +1,925 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkPositionIndexes;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.io.GwtWorkarounds.asCharInput;
|
||||
import static com.google.common.io.GwtWorkarounds.asCharOutput;
|
||||
import static com.google.common.io.GwtWorkarounds.asInputStream;
|
||||
import static com.google.common.io.GwtWorkarounds.asOutputStream;
|
||||
import static com.google.common.io.GwtWorkarounds.stringBuilderOutput;
|
||||
import static com.google.common.math.IntMath.divide;
|
||||
import static com.google.common.math.IntMath.log2;
|
||||
import static java.math.RoundingMode.CEILING;
|
||||
import static java.math.RoundingMode.FLOOR;
|
||||
import static java.math.RoundingMode.UNNECESSARY;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.io.GwtWorkarounds.ByteInput;
|
||||
import com.google.common.io.GwtWorkarounds.ByteOutput;
|
||||
import com.google.common.io.GwtWorkarounds.CharInput;
|
||||
import com.google.common.io.GwtWorkarounds.CharOutput;
|
||||
|
||||
/**
|
||||
* A binary encoding scheme for reversibly translating between byte sequences
|
||||
* and printable ASCII strings. This class includes several constants for
|
||||
* encoding schemes specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648">RFC 4648</a>. For example, the
|
||||
* expression:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* BaseEncoding.base32().encode("foo".getBytes(Charsets.US_ASCII))}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* returns the string {@code "MZXW6==="}, and
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* @code
|
||||
* byte[] decoded = BaseEncoding.base32().decode("MZXW6===");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* ...returns the ASCII bytes of the string {@code "foo"}.
|
||||
*
|
||||
* <p>
|
||||
* By default, {@code BaseEncoding}'s behavior is relatively strict and in
|
||||
* accordance with RFC 4648. Decoding rejects characters in the wrong case,
|
||||
* though padding is optional. To modify encoding and decoding behavior, use
|
||||
* configuration methods to obtain a new encoding with modified behavior:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* BaseEncoding.base16().lowerCase().decode("deadbeef");}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Warning: BaseEncoding instances are immutable. Invoking a configuration
|
||||
* method has no effect on the receiving instance; you must store and use the
|
||||
* new encoding instance it returns, instead.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* // Do NOT do this
|
||||
* BaseEncoding hex = BaseEncoding.base16();
|
||||
* hex.lowerCase(); // does nothing!
|
||||
* return hex.decode("deadbeef"); // throws an IllegalArgumentException}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* It is guaranteed that {@code encoding.decode(encoding.encode(x))} is always
|
||||
* equal to {@code x}, but the reverse does not necessarily hold.
|
||||
*
|
||||
* <p>
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Encoding
|
||||
* <th>Alphabet
|
||||
* <th>{@code char:byte} ratio
|
||||
* <th>Default padding
|
||||
* <th>Comments
|
||||
* <tr>
|
||||
* <td>{@link #base16()}
|
||||
* <td>0-9 A-F
|
||||
* <td>2.00
|
||||
* <td>N/A
|
||||
* <td>Traditional hexadecimal. Defaults to upper case.
|
||||
* <tr>
|
||||
* <td>{@link #base32()}
|
||||
* <td>A-Z 2-7
|
||||
* <td>1.60
|
||||
* <td>=
|
||||
* <td>Human-readable; no possibility of mixing up 0/O or 1/I. Defaults to upper
|
||||
* case.
|
||||
* <tr>
|
||||
* <td>{@link #base32Hex()}
|
||||
* <td>0-9 A-V
|
||||
* <td>1.60
|
||||
* <td>=
|
||||
* <td>"Numerical" base 32; extended from the traditional hex alphabet. Defaults
|
||||
* to upper case.
|
||||
* <tr>
|
||||
* <td>{@link #base64()}
|
||||
* <td>A-Z a-z 0-9 + /
|
||||
* <td>1.33
|
||||
* <td>=
|
||||
* <td>
|
||||
* <tr>
|
||||
* <td>{@link #base64Url()}
|
||||
* <td>A-Z a-z 0-9 - _
|
||||
* <td>1.33
|
||||
* <td>=
|
||||
* <td>Safe to use as filenames, or to pass in URLs without escaping
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* All instances of this class are immutable, so they may be stored safely as
|
||||
* static constants.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @since 14.0
|
||||
*/
|
||||
@Beta
|
||||
@GwtCompatible(emulated = true)
|
||||
public abstract class BaseEncoding {
|
||||
// TODO(user): consider adding encodeTo(Appendable, byte[], [int, int])
|
||||
|
||||
BaseEncoding() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception indicating invalid base-encoded input encountered while decoding.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @since 15.0
|
||||
*/
|
||||
public static final class DecodingException extends IOException {
|
||||
DecodingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
DecodingException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the specified byte array, and returns the encoded {@code String}.
|
||||
*/
|
||||
public String encode(byte[] bytes) {
|
||||
return encode(checkNotNull(bytes), 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the specified range of the specified byte array, and returns the
|
||||
* encoded {@code String}.
|
||||
*/
|
||||
public final String encode(byte[] bytes, int off, int len) {
|
||||
checkNotNull(bytes);
|
||||
checkPositionIndexes(off, off + len, bytes.length);
|
||||
CharOutput result = stringBuilderOutput(maxEncodedSize(len));
|
||||
ByteOutput byteOutput = encodingStream(result);
|
||||
try {
|
||||
for (int i = 0; i < len; i++) {
|
||||
byteOutput.write(bytes[off + i]);
|
||||
}
|
||||
byteOutput.close();
|
||||
} catch (IOException impossible) {
|
||||
throw new AssertionError("impossible");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code OutputStream} that encodes bytes using this encoding into
|
||||
* the specified {@code Writer}. When the returned {@code OutputStream} is
|
||||
* closed, so is the backing {@code Writer}.
|
||||
*/
|
||||
@GwtIncompatible("Writer,OutputStream")
|
||||
public final OutputStream encodingStream(Writer writer) {
|
||||
return asOutputStream(encodingStream(asCharOutput(writer)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code ByteSink} that writes base-encoded bytes to the specified
|
||||
* {@code CharSink}.
|
||||
*/
|
||||
@GwtIncompatible("ByteSink,CharSink")
|
||||
public final ByteSink encodingSink(final CharSink encodedSink) {
|
||||
checkNotNull(encodedSink);
|
||||
return new ByteSink() {
|
||||
@Override
|
||||
public OutputStream openStream() throws IOException {
|
||||
return encodingStream(encodedSink.openStream());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO(user): document the extent of leniency, probably after adding
|
||||
// ignore(CharMatcher)
|
||||
|
||||
private static byte[] extract(byte[] result, int length) {
|
||||
if (length == result.length) {
|
||||
return result;
|
||||
} else {
|
||||
byte[] trunc = new byte[length];
|
||||
System.arraycopy(result, 0, trunc, 0, length);
|
||||
return trunc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the specified character sequence, and returns the resulting
|
||||
* {@code byte[]}. This is the inverse operation to {@link #encode(byte[])}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the input is not a valid encoded string
|
||||
* according to this encoding.
|
||||
*/
|
||||
public final byte[] decode(CharSequence chars) {
|
||||
try {
|
||||
return decodeChecked(chars);
|
||||
} catch (DecodingException badInput) {
|
||||
throw new IllegalArgumentException(badInput);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the specified character sequence, and returns the resulting
|
||||
* {@code byte[]}. This is the inverse operation to {@link #encode(byte[])}.
|
||||
*
|
||||
* @throws DecodingException if the input is not a valid encoded string
|
||||
* according to this encoding.
|
||||
*/
|
||||
final byte[] decodeChecked(CharSequence chars) throws DecodingException {
|
||||
chars = padding().trimTrailingFrom(chars);
|
||||
ByteInput decodedInput = decodingStream(asCharInput(chars));
|
||||
byte[] tmp = new byte[maxDecodedSize(chars.length())];
|
||||
int index = 0;
|
||||
try {
|
||||
for (int i = decodedInput.read(); i != -1; i = decodedInput.read()) {
|
||||
tmp[index++] = (byte) i;
|
||||
}
|
||||
} catch (DecodingException badInput) {
|
||||
throw badInput;
|
||||
} catch (IOException impossible) {
|
||||
throw new AssertionError(impossible);
|
||||
}
|
||||
return extract(tmp, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code InputStream} that decodes base-encoded input from the
|
||||
* specified {@code Reader}. The returned stream throws a
|
||||
* {@link DecodingException} upon decoding-specific errors.
|
||||
*/
|
||||
@GwtIncompatible("Reader,InputStream")
|
||||
public final InputStream decodingStream(Reader reader) {
|
||||
return asInputStream(decodingStream(asCharInput(reader)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code ByteSource} that reads base-encoded bytes from the specified
|
||||
* {@code CharSource}.
|
||||
*/
|
||||
@GwtIncompatible("ByteSource,CharSource")
|
||||
public final ByteSource decodingSource(final CharSource encodedSource) {
|
||||
checkNotNull(encodedSource);
|
||||
return new ByteSource() {
|
||||
@Override
|
||||
public InputStream openStream() throws IOException {
|
||||
return decodingStream(encodedSource.openStream());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Implementations for encoding/decoding
|
||||
|
||||
abstract int maxEncodedSize(int bytes);
|
||||
|
||||
abstract ByteOutput encodingStream(CharOutput charOutput);
|
||||
|
||||
abstract int maxDecodedSize(int chars);
|
||||
|
||||
abstract ByteInput decodingStream(CharInput charInput);
|
||||
|
||||
abstract CharMatcher padding();
|
||||
|
||||
// Modified encoding generators
|
||||
|
||||
/**
|
||||
* Returns an encoding that behaves equivalently to this encoding, but omits any
|
||||
* padding characters as specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-3.2">RFC 4648 section
|
||||
* 3.2</a>, Padding of Encoded Data.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public abstract BaseEncoding omitPadding();
|
||||
|
||||
/**
|
||||
* Returns an encoding that behaves equivalently to this encoding, but uses an
|
||||
* alternate character for padding.
|
||||
*
|
||||
* @throws IllegalArgumentException if this padding character is already used in
|
||||
* the alphabet or a separator
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public abstract BaseEncoding withPadChar(char padChar);
|
||||
|
||||
/**
|
||||
* Returns an encoding that behaves equivalently to this encoding, but adds a
|
||||
* separator string after every {@code n} characters. Any occurrences of any
|
||||
* characters that occur in the separator are skipped over in decoding.
|
||||
*
|
||||
* @throws IllegalArgumentException if any alphabet or padding characters
|
||||
* appear in the separator string, or if
|
||||
* {@code n <= 0}
|
||||
* @throws UnsupportedOperationException if this encoding already uses a
|
||||
* separator
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public abstract BaseEncoding withSeparator(String separator, int n);
|
||||
|
||||
/**
|
||||
* Returns an encoding that behaves equivalently to this encoding, but encodes
|
||||
* and decodes with uppercase letters. Padding and separator characters remain
|
||||
* in their original case.
|
||||
*
|
||||
* @throws IllegalStateException if the alphabet used by this encoding contains
|
||||
* mixed upper- and lower-case characters
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public abstract BaseEncoding upperCase();
|
||||
|
||||
/**
|
||||
* Returns an encoding that behaves equivalently to this encoding, but encodes
|
||||
* and decodes with lowercase letters. Padding and separator characters remain
|
||||
* in their original case.
|
||||
*
|
||||
* @throws IllegalStateException if the alphabet used by this encoding contains
|
||||
* mixed upper- and lower-case characters
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public abstract BaseEncoding lowerCase();
|
||||
|
||||
private static final BaseEncoding BASE64 = new StandardBaseEncoding("base64()",
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", '=');
|
||||
|
||||
/**
|
||||
* The "base64" base encoding specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-4">RFC 4648 section
|
||||
* 4</a>, Base 64 Encoding. (This is the same as the base 64 encoding from
|
||||
* <a href="http://tools.ietf.org/html/rfc3548#section-3">RFC 3548</a>.)
|
||||
*
|
||||
* <p>
|
||||
* The character {@code '='} is used for padding, but can be
|
||||
* {@linkplain #omitPadding() omitted} or {@linkplain #withPadChar(char)
|
||||
* replaced}.
|
||||
*
|
||||
* <p>
|
||||
* No line feeds are added by default, as per
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section
|
||||
* 3.1</a>, Line Feeds in Encoded Data. Line feeds may be added using
|
||||
* {@link #withSeparator(String, int)}.
|
||||
*/
|
||||
public static BaseEncoding base64() {
|
||||
return BASE64;
|
||||
}
|
||||
|
||||
private static final BaseEncoding BASE64_URL = new StandardBaseEncoding("base64Url()",
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", '=');
|
||||
|
||||
/**
|
||||
* The "base64url" encoding specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-5">RFC 4648 section
|
||||
* 5</a>, Base 64 Encoding with URL and Filename Safe Alphabet, also sometimes
|
||||
* referred to as the "web safe Base64." (This is the same as the base 64
|
||||
* encoding with URL and filename safe alphabet from
|
||||
* <a href="http://tools.ietf.org/html/rfc3548#section-4">RFC 3548</a>.)
|
||||
*
|
||||
* <p>
|
||||
* The character {@code '='} is used for padding, but can be
|
||||
* {@linkplain #omitPadding() omitted} or {@linkplain #withPadChar(char)
|
||||
* replaced}.
|
||||
*
|
||||
* <p>
|
||||
* No line feeds are added by default, as per
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section
|
||||
* 3.1</a>, Line Feeds in Encoded Data. Line feeds may be added using
|
||||
* {@link #withSeparator(String, int)}.
|
||||
*/
|
||||
public static BaseEncoding base64Url() {
|
||||
return BASE64_URL;
|
||||
}
|
||||
|
||||
private static final BaseEncoding BASE32 = new StandardBaseEncoding("base32()", "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
||||
'=');
|
||||
|
||||
/**
|
||||
* The "base32" encoding specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-6">RFC 4648 section
|
||||
* 6</a>, Base 32 Encoding. (This is the same as the base 32 encoding from
|
||||
* <a href="http://tools.ietf.org/html/rfc3548#section-5">RFC 3548</a>.)
|
||||
*
|
||||
* <p>
|
||||
* The character {@code '='} is used for padding, but can be
|
||||
* {@linkplain #omitPadding() omitted} or {@linkplain #withPadChar(char)
|
||||
* replaced}.
|
||||
*
|
||||
* <p>
|
||||
* No line feeds are added by default, as per
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section
|
||||
* 3.1</a>, Line Feeds in Encoded Data. Line feeds may be added using
|
||||
* {@link #withSeparator(String, int)}.
|
||||
*/
|
||||
public static BaseEncoding base32() {
|
||||
return BASE32;
|
||||
}
|
||||
|
||||
private static final BaseEncoding BASE32_HEX = new StandardBaseEncoding("base32Hex()",
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUV", '=');
|
||||
|
||||
/**
|
||||
* The "base32hex" encoding specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-7">RFC 4648 section
|
||||
* 7</a>, Base 32 Encoding with Extended Hex Alphabet. There is no corresponding
|
||||
* encoding in RFC 3548.
|
||||
*
|
||||
* <p>
|
||||
* The character {@code '='} is used for padding, but can be
|
||||
* {@linkplain #omitPadding() omitted} or {@linkplain #withPadChar(char)
|
||||
* replaced}.
|
||||
*
|
||||
* <p>
|
||||
* No line feeds are added by default, as per
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section
|
||||
* 3.1</a>, Line Feeds in Encoded Data. Line feeds may be added using
|
||||
* {@link #withSeparator(String, int)}.
|
||||
*/
|
||||
public static BaseEncoding base32Hex() {
|
||||
return BASE32_HEX;
|
||||
}
|
||||
|
||||
private static final BaseEncoding BASE16 = new StandardBaseEncoding("base16()", "0123456789ABCDEF", null);
|
||||
|
||||
/**
|
||||
* The "base16" encoding specified by
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-8">RFC 4648 section
|
||||
* 8</a>, Base 16 Encoding. (This is the same as the base 16 encoding from
|
||||
* <a href="http://tools.ietf.org/html/rfc3548#section-6">RFC 3548</a>.) This is
|
||||
* commonly known as "hexadecimal" format.
|
||||
*
|
||||
* <p>
|
||||
* No padding is necessary in base 16, so {@link #withPadChar(char)} and
|
||||
* {@link #omitPadding()} have no effect.
|
||||
*
|
||||
* <p>
|
||||
* No line feeds are added by default, as per
|
||||
* <a href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section
|
||||
* 3.1</a>, Line Feeds in Encoded Data. Line feeds may be added using
|
||||
* {@link #withSeparator(String, int)}.
|
||||
*/
|
||||
public static BaseEncoding base16() {
|
||||
return BASE16;
|
||||
}
|
||||
|
||||
private static final class Alphabet extends CharMatcher {
|
||||
private final String name;
|
||||
// this is meant to be immutable -- don't modify it!
|
||||
private final char[] chars;
|
||||
final int mask;
|
||||
final int bitsPerChar;
|
||||
final int charsPerChunk;
|
||||
final int bytesPerChunk;
|
||||
private final byte[] decodabet;
|
||||
private final boolean[] validPadding;
|
||||
|
||||
Alphabet(String name, char[] chars) {
|
||||
this.name = checkNotNull(name);
|
||||
this.chars = checkNotNull(chars);
|
||||
try {
|
||||
this.bitsPerChar = log2(chars.length, UNNECESSARY);
|
||||
} catch (ArithmeticException e) {
|
||||
throw new IllegalArgumentException("Illegal alphabet length " + chars.length, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* e.g. for base64, bitsPerChar == 6, charsPerChunk == 4, and bytesPerChunk ==
|
||||
* 3. This makes for the smallest chunk size that still has charsPerChunk *
|
||||
* bitsPerChar be a multiple of 8.
|
||||
*/
|
||||
int gcd = Math.min(8, Integer.lowestOneBit(bitsPerChar));
|
||||
this.charsPerChunk = 8 / gcd;
|
||||
this.bytesPerChunk = bitsPerChar / gcd;
|
||||
|
||||
this.mask = chars.length - 1;
|
||||
|
||||
byte[] decodabet = new byte[Ascii.MAX + 1];
|
||||
Arrays.fill(decodabet, (byte) -1);
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
checkArgument(CharMatcher.ASCII.matches(c), "Non-ASCII character: %s", c);
|
||||
checkArgument(decodabet[c] == -1, "Duplicate character: %s", c);
|
||||
decodabet[c] = (byte) i;
|
||||
}
|
||||
this.decodabet = decodabet;
|
||||
|
||||
boolean[] validPadding = new boolean[charsPerChunk];
|
||||
for (int i = 0; i < bytesPerChunk; i++) {
|
||||
validPadding[divide(i * 8, bitsPerChar, CEILING)] = true;
|
||||
}
|
||||
this.validPadding = validPadding;
|
||||
}
|
||||
|
||||
char encode(int bits) {
|
||||
return chars[bits];
|
||||
}
|
||||
|
||||
boolean isValidPaddingStartPosition(int index) {
|
||||
return validPadding[index % charsPerChunk];
|
||||
}
|
||||
|
||||
int decode(char ch) throws IOException {
|
||||
if (ch > Ascii.MAX || decodabet[ch] == -1) {
|
||||
throw new DecodingException("Unrecognized character: " + ch);
|
||||
}
|
||||
return decodabet[ch];
|
||||
}
|
||||
|
||||
private boolean hasLowerCase() {
|
||||
for (char c : chars) {
|
||||
if (Ascii.isLowerCase(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasUpperCase() {
|
||||
for (char c : chars) {
|
||||
if (Ascii.isUpperCase(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Alphabet upperCase() {
|
||||
if (!hasLowerCase()) {
|
||||
return this;
|
||||
} else {
|
||||
checkState(!hasUpperCase(), "Cannot call upperCase() on a mixed-case alphabet");
|
||||
char[] upperCased = new char[chars.length];
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
upperCased[i] = Ascii.toUpperCase(chars[i]);
|
||||
}
|
||||
return new Alphabet(name + ".upperCase()", upperCased);
|
||||
}
|
||||
}
|
||||
|
||||
Alphabet lowerCase() {
|
||||
if (!hasUpperCase()) {
|
||||
return this;
|
||||
} else {
|
||||
checkState(!hasLowerCase(), "Cannot call lowerCase() on a mixed-case alphabet");
|
||||
char[] lowerCased = new char[chars.length];
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
lowerCased[i] = Ascii.toLowerCase(chars[i]);
|
||||
}
|
||||
return new Alphabet(name + ".lowerCase()", lowerCased);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(char c) {
|
||||
return CharMatcher.ASCII.matches(c) && decodabet[c] != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
static final class StandardBaseEncoding extends BaseEncoding {
|
||||
// TODO(user): provide a useful toString
|
||||
private final Alphabet alphabet;
|
||||
|
||||
@Nullable
|
||||
private final Character paddingChar;
|
||||
|
||||
StandardBaseEncoding(String name, String alphabetChars, @Nullable Character paddingChar) {
|
||||
this(new Alphabet(name, alphabetChars.toCharArray()), paddingChar);
|
||||
}
|
||||
|
||||
StandardBaseEncoding(Alphabet alphabet, @Nullable Character paddingChar) {
|
||||
this.alphabet = checkNotNull(alphabet);
|
||||
checkArgument(paddingChar == null || !alphabet.matches(paddingChar),
|
||||
"Padding character %s was already in alphabet", paddingChar);
|
||||
this.paddingChar = paddingChar;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharMatcher padding() {
|
||||
return (paddingChar == null) ? CharMatcher.NONE : CharMatcher.is(paddingChar.charValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
int maxEncodedSize(int bytes) {
|
||||
return alphabet.charsPerChunk * divide(bytes, alphabet.bytesPerChunk, CEILING);
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteOutput encodingStream(final CharOutput out) {
|
||||
checkNotNull(out);
|
||||
return new ByteOutput() {
|
||||
int bitBuffer = 0;
|
||||
int bitBufferLength = 0;
|
||||
int writtenChars = 0;
|
||||
|
||||
@Override
|
||||
public void write(byte b) throws IOException {
|
||||
bitBuffer <<= 8;
|
||||
bitBuffer |= b & 0xFF;
|
||||
bitBufferLength += 8;
|
||||
while (bitBufferLength >= alphabet.bitsPerChar) {
|
||||
int charIndex = (bitBuffer >> (bitBufferLength - alphabet.bitsPerChar)) & alphabet.mask;
|
||||
out.write(alphabet.encode(charIndex));
|
||||
writtenChars++;
|
||||
bitBufferLength -= alphabet.bitsPerChar;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (bitBufferLength > 0) {
|
||||
int charIndex = (bitBuffer << (alphabet.bitsPerChar - bitBufferLength)) & alphabet.mask;
|
||||
out.write(alphabet.encode(charIndex));
|
||||
writtenChars++;
|
||||
if (paddingChar != null) {
|
||||
while (writtenChars % alphabet.charsPerChunk != 0) {
|
||||
out.write(paddingChar.charValue());
|
||||
writtenChars++;
|
||||
}
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
int maxDecodedSize(int chars) {
|
||||
return (int) ((alphabet.bitsPerChar * (long) chars + 7L) / 8L);
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteInput decodingStream(final CharInput reader) {
|
||||
checkNotNull(reader);
|
||||
return new ByteInput() {
|
||||
int bitBuffer = 0;
|
||||
int bitBufferLength = 0;
|
||||
int readChars = 0;
|
||||
boolean hitPadding = false;
|
||||
final CharMatcher paddingMatcher = padding();
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
while (true) {
|
||||
int readChar = reader.read();
|
||||
if (readChar == -1) {
|
||||
if (!hitPadding && !alphabet.isValidPaddingStartPosition(readChars)) {
|
||||
throw new DecodingException("Invalid input length " + readChars);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
readChars++;
|
||||
char ch = (char) readChar;
|
||||
if (paddingMatcher.matches(ch)) {
|
||||
if (!hitPadding
|
||||
&& (readChars == 1 || !alphabet.isValidPaddingStartPosition(readChars - 1))) {
|
||||
throw new DecodingException("Padding cannot start at index " + readChars);
|
||||
}
|
||||
hitPadding = true;
|
||||
} else if (hitPadding) {
|
||||
throw new DecodingException(
|
||||
"Expected padding character but found '" + ch + "' at index " + readChars);
|
||||
} else {
|
||||
bitBuffer <<= alphabet.bitsPerChar;
|
||||
bitBuffer |= alphabet.decode(ch);
|
||||
bitBufferLength += alphabet.bitsPerChar;
|
||||
|
||||
if (bitBufferLength >= 8) {
|
||||
bitBufferLength -= 8;
|
||||
return (bitBuffer >> bitBufferLength) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
reader.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding omitPadding() {
|
||||
return (paddingChar == null) ? this : new StandardBaseEncoding(alphabet, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding withPadChar(char padChar) {
|
||||
if (8 % alphabet.bitsPerChar == 0 || (paddingChar != null && paddingChar.charValue() == padChar)) {
|
||||
return this;
|
||||
} else {
|
||||
return new StandardBaseEncoding(alphabet, padChar);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding withSeparator(String separator, int afterEveryChars) {
|
||||
checkNotNull(separator);
|
||||
checkArgument(padding().or(alphabet).matchesNoneOf(separator),
|
||||
"Separator cannot contain alphabet or padding characters");
|
||||
return new SeparatedBaseEncoding(this, separator, afterEveryChars);
|
||||
}
|
||||
|
||||
private transient BaseEncoding upperCase;
|
||||
private transient BaseEncoding lowerCase;
|
||||
|
||||
@Override
|
||||
public BaseEncoding upperCase() {
|
||||
BaseEncoding result = upperCase;
|
||||
if (result == null) {
|
||||
Alphabet upper = alphabet.upperCase();
|
||||
result = upperCase = (upper == alphabet) ? this : new StandardBaseEncoding(upper, paddingChar);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding lowerCase() {
|
||||
BaseEncoding result = lowerCase;
|
||||
if (result == null) {
|
||||
Alphabet lower = alphabet.lowerCase();
|
||||
result = lowerCase = (lower == alphabet) ? this : new StandardBaseEncoding(lower, paddingChar);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("BaseEncoding.");
|
||||
builder.append(alphabet.toString());
|
||||
if (8 % alphabet.bitsPerChar != 0) {
|
||||
if (paddingChar == null) {
|
||||
builder.append(".omitPadding()");
|
||||
} else {
|
||||
builder.append(".withPadChar(").append(paddingChar).append(')');
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static CharInput ignoringInput(final CharInput delegate, final CharMatcher toIgnore) {
|
||||
checkNotNull(delegate);
|
||||
checkNotNull(toIgnore);
|
||||
return new CharInput() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int readChar;
|
||||
do {
|
||||
readChar = delegate.read();
|
||||
} while (readChar != -1 && toIgnore.matches((char) readChar));
|
||||
return readChar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
delegate.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static CharOutput separatingOutput(final CharOutput delegate, final String separator, final int afterEveryChars) {
|
||||
checkNotNull(delegate);
|
||||
checkNotNull(separator);
|
||||
checkArgument(afterEveryChars > 0);
|
||||
return new CharOutput() {
|
||||
int charsUntilSeparator = afterEveryChars;
|
||||
|
||||
@Override
|
||||
public void write(char c) throws IOException {
|
||||
if (charsUntilSeparator == 0) {
|
||||
for (int i = 0; i < separator.length(); i++) {
|
||||
delegate.write(separator.charAt(i));
|
||||
}
|
||||
charsUntilSeparator = afterEveryChars;
|
||||
}
|
||||
delegate.write(c);
|
||||
charsUntilSeparator--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
delegate.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
delegate.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static final class SeparatedBaseEncoding extends BaseEncoding {
|
||||
private final BaseEncoding delegate;
|
||||
private final String separator;
|
||||
private final int afterEveryChars;
|
||||
private final CharMatcher separatorChars;
|
||||
|
||||
SeparatedBaseEncoding(BaseEncoding delegate, String separator, int afterEveryChars) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.separator = checkNotNull(separator);
|
||||
this.afterEveryChars = afterEveryChars;
|
||||
checkArgument(afterEveryChars > 0, "Cannot add a separator after every %s chars", afterEveryChars);
|
||||
this.separatorChars = CharMatcher.anyOf(separator).precomputed();
|
||||
}
|
||||
|
||||
@Override
|
||||
CharMatcher padding() {
|
||||
return delegate.padding();
|
||||
}
|
||||
|
||||
@Override
|
||||
int maxEncodedSize(int bytes) {
|
||||
int unseparatedSize = delegate.maxEncodedSize(bytes);
|
||||
return unseparatedSize
|
||||
+ separator.length() * divide(Math.max(0, unseparatedSize - 1), afterEveryChars, FLOOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteOutput encodingStream(final CharOutput output) {
|
||||
return delegate.encodingStream(separatingOutput(output, separator, afterEveryChars));
|
||||
}
|
||||
|
||||
@Override
|
||||
int maxDecodedSize(int chars) {
|
||||
return delegate.maxDecodedSize(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteInput decodingStream(final CharInput input) {
|
||||
return delegate.decodingStream(ignoringInput(input, separatorChars));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding omitPadding() {
|
||||
return delegate.omitPadding().withSeparator(separator, afterEveryChars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding withPadChar(char padChar) {
|
||||
return delegate.withPadChar(padChar).withSeparator(separator, afterEveryChars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding withSeparator(String separator, int afterEveryChars) {
|
||||
throw new UnsupportedOperationException("Already have a separator");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding upperCase() {
|
||||
return delegate.upperCase().withSeparator(separator, afterEveryChars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEncoding lowerCase() {
|
||||
return delegate.lowerCase().withSeparator(separator, afterEveryChars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString() + ".withSeparator(\"" + separator + "\", " + afterEveryChars + ")";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An extension of {@code DataInput} for reading from in-memory byte arrays; its
|
||||
* methods offer identical functionality but do not throw {@link IOException}.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:<b> The caller is responsible for not attempting to read past the
|
||||
* end of the array. If any method encounters the end of the array prematurely,
|
||||
* it throws {@link IllegalStateException} to signify <i>programmer error</i>.
|
||||
* This behavior is a technical violation of the supertype's contract, which
|
||||
* specifies a checked exception.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface ByteArrayDataInput extends DataInput {
|
||||
@Override
|
||||
void readFully(byte b[]);
|
||||
|
||||
@Override
|
||||
void readFully(byte b[], int off, int len);
|
||||
|
||||
@Override
|
||||
int skipBytes(int n);
|
||||
|
||||
@Override
|
||||
boolean readBoolean();
|
||||
|
||||
@Override
|
||||
byte readByte();
|
||||
|
||||
@Override
|
||||
int readUnsignedByte();
|
||||
|
||||
@Override
|
||||
short readShort();
|
||||
|
||||
@Override
|
||||
int readUnsignedShort();
|
||||
|
||||
@Override
|
||||
char readChar();
|
||||
|
||||
@Override
|
||||
int readInt();
|
||||
|
||||
@Override
|
||||
long readLong();
|
||||
|
||||
@Override
|
||||
float readFloat();
|
||||
|
||||
@Override
|
||||
double readDouble();
|
||||
|
||||
@Override
|
||||
String readLine();
|
||||
|
||||
@Override
|
||||
String readUTF();
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An extension of {@code DataOutput} for writing to in-memory byte arrays; its
|
||||
* methods offer identical functionality but do not throw {@link IOException}.
|
||||
*
|
||||
* @author Jayaprabhakar Kadarkarai
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface ByteArrayDataOutput extends DataOutput {
|
||||
@Override
|
||||
void write(int b);
|
||||
|
||||
@Override
|
||||
void write(byte b[]);
|
||||
|
||||
@Override
|
||||
void write(byte b[], int off, int len);
|
||||
|
||||
@Override
|
||||
void writeBoolean(boolean v);
|
||||
|
||||
@Override
|
||||
void writeByte(int v);
|
||||
|
||||
@Override
|
||||
void writeShort(int v);
|
||||
|
||||
@Override
|
||||
void writeChar(int v);
|
||||
|
||||
@Override
|
||||
void writeInt(int v);
|
||||
|
||||
@Override
|
||||
void writeLong(long v);
|
||||
|
||||
@Override
|
||||
void writeFloat(float v);
|
||||
|
||||
@Override
|
||||
void writeDouble(double v);
|
||||
|
||||
@Override
|
||||
void writeChars(String s);
|
||||
|
||||
@Override
|
||||
void writeUTF(String s);
|
||||
|
||||
/**
|
||||
* @deprecated This method is dangerous as it discards the high byte of every
|
||||
* character. For UTF-8, use
|
||||
* {@code write(s.getBytes(Charsets.UTF_8))}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
void writeBytes(String s);
|
||||
|
||||
/**
|
||||
* Returns the contents that have been written to this instance, as a byte
|
||||
* array.
|
||||
*/
|
||||
byte[] toByteArray();
|
||||
}
|
49
sources/main/java/com/google/common/io/ByteProcessor.java
Normal file
49
sources/main/java/com/google/common/io/ByteProcessor.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* A callback interface to process bytes from a stream.
|
||||
*
|
||||
* <p>
|
||||
* {@link #processBytes} will be called for each line that is read, and should
|
||||
* return {@code false} when you want to stop processing.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public interface ByteProcessor<T> {
|
||||
/**
|
||||
* This method will be called for each chunk of bytes in an input stream. The
|
||||
* implementation should process the bytes from {@code buf[off]} through
|
||||
* {@code buf[off + len - 1]} (inclusive).
|
||||
*
|
||||
* @param buf the byte array containing the data to process
|
||||
* @param off the initial offset into the array
|
||||
* @param len the length of data to be processed
|
||||
* @return true to continue processing, false to stop
|
||||
*/
|
||||
boolean processBytes(byte[] buf, int off, int len) throws IOException;
|
||||
|
||||
/** Return the result of processing all the bytes. */
|
||||
T getResult();
|
||||
}
|
180
sources/main/java/com/google/common/io/ByteSink.java
Normal file
180
sources/main/java/com/google/common/io/ByteSink.java
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* A destination to which bytes can be written, such as a file. Unlike an
|
||||
* {@link OutputStream}, a {@code ByteSink} is not an open, stateful stream that
|
||||
* can be written to and closed. Instead, it is an immutable <i>supplier</i> of
|
||||
* {@code OutputStream} instances.
|
||||
*
|
||||
* <p>
|
||||
* {@code ByteSink} provides two kinds of methods:
|
||||
* <ul>
|
||||
* <li><b>Methods that return a stream:</b> These methods should return a
|
||||
* <i>new</i>, independent instance each time they are called. The caller is
|
||||
* responsible for ensuring that the returned stream is closed.
|
||||
* <li><b>Convenience methods:</b> These are implementations of common
|
||||
* operations that are typically implemented by opening a stream using one of
|
||||
* the methods in the first category, doing something and finally closing the
|
||||
* stream or channel that was opened.
|
||||
* </ul>
|
||||
*
|
||||
* @since 14.0
|
||||
* @author Colin Decker
|
||||
*/
|
||||
public abstract class ByteSink implements OutputSupplier<OutputStream> {
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses.
|
||||
*/
|
||||
protected ByteSink() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link CharSink} view of this {@code ByteSink} that writes
|
||||
* characters to this sink as bytes encoded with the given {@link Charset
|
||||
* charset}.
|
||||
*/
|
||||
public CharSink asCharSink(Charset charset) {
|
||||
return new AsCharSink(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new {@link OutputStream} for writing to this sink. This method should
|
||||
* return a new, independent stream each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned stream is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* stream
|
||||
*/
|
||||
public abstract OutputStream openStream() throws IOException;
|
||||
|
||||
/**
|
||||
* This method is a temporary method provided for easing migration from
|
||||
* suppliers to sources and sinks.
|
||||
*
|
||||
* @since 15.0
|
||||
* @deprecated This method is only provided for temporary compatibility with the
|
||||
* {@link OutputSupplier} interface and should not be called
|
||||
* directly. Use {@link #openStream} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final OutputStream getOutput() throws IOException {
|
||||
return openStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new buffered {@link OutputStream} for writing to this sink. The
|
||||
* returned stream is not required to be a {@link BufferedOutputStream} in order
|
||||
* to allow implementations to simply delegate to {@link #openStream()} when the
|
||||
* stream returned by that method does not benefit from additional buffering
|
||||
* (for example, a {@code ByteArrayOutputStream}). This method should return a
|
||||
* new, independent stream each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned stream is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* stream
|
||||
* @since 15.0 (in 14.0 with return type {@link BufferedOutputStream})
|
||||
*/
|
||||
public OutputStream openBufferedStream() throws IOException {
|
||||
OutputStream out = openStream();
|
||||
return (out instanceof BufferedOutputStream) ? (BufferedOutputStream) out : new BufferedOutputStream(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all the given bytes to this sink.
|
||||
*
|
||||
* @throws IOException if an I/O occurs in the process of writing to this sink
|
||||
*/
|
||||
public void write(byte[] bytes) throws IOException {
|
||||
checkNotNull(bytes);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
OutputStream out = closer.register(openStream());
|
||||
out.write(bytes);
|
||||
out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all the bytes from the given {@code InputStream} to this sink. Does
|
||||
* not close {@code input}.
|
||||
*
|
||||
* @throws IOException if an I/O occurs in the process of reading from
|
||||
* {@code input} or writing to this sink
|
||||
*/
|
||||
public long writeFrom(InputStream input) throws IOException {
|
||||
checkNotNull(input);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
OutputStream out = closer.register(openStream());
|
||||
long written = ByteStreams.copy(input, out);
|
||||
out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
|
||||
return written;
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A char sink that encodes written characters with a charset and writes
|
||||
* resulting bytes to this byte sink.
|
||||
*/
|
||||
private final class AsCharSink extends CharSink {
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
private AsCharSink(Charset charset) {
|
||||
this.charset = checkNotNull(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer openStream() throws IOException {
|
||||
return new OutputStreamWriter(ByteSink.this.openStream(), charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ByteSink.this.toString() + ".asCharSink(" + charset + ")";
|
||||
}
|
||||
}
|
||||
}
|
652
sources/main/java/com/google/common/io/ByteSource.java
Normal file
652
sources/main/java/com/google/common/io/ByteSource.java
Normal file
@ -0,0 +1,652 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.hash.Funnels;
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hasher;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
|
||||
/**
|
||||
* A readable source of bytes, such as a file. Unlike an {@link InputStream}, a
|
||||
* {@code ByteSource} is not an open, stateful stream for input that can be read
|
||||
* and closed. Instead, it is an immutable <i>supplier</i> of
|
||||
* {@code InputStream} instances.
|
||||
*
|
||||
* <p>
|
||||
* {@code ByteSource} provides two kinds of methods:
|
||||
* <ul>
|
||||
* <li><b>Methods that return a stream:</b> These methods should return a
|
||||
* <i>new</i>, independent instance each time they are called. The caller is
|
||||
* responsible for ensuring that the returned stream is closed.
|
||||
* <li><b>Convenience methods:</b> These are implementations of common
|
||||
* operations that are typically implemented by opening a stream using one of
|
||||
* the methods in the first category, doing something and finally closing the
|
||||
* stream that was opened.
|
||||
* </ul>
|
||||
*
|
||||
* @since 14.0
|
||||
* @author Colin Decker
|
||||
*/
|
||||
public abstract class ByteSource implements InputSupplier<InputStream> {
|
||||
|
||||
private static final int BUF_SIZE = 0x1000; // 4K
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses.
|
||||
*/
|
||||
protected ByteSource() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link CharSource} view of this byte source that decodes bytes read
|
||||
* from this source as characters using the given {@link Charset}.
|
||||
*/
|
||||
public CharSource asCharSource(Charset charset) {
|
||||
return new AsCharSource(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new {@link InputStream} for reading from this source. This method
|
||||
* should return a new, independent stream each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned stream is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* stream
|
||||
*/
|
||||
public abstract InputStream openStream() throws IOException;
|
||||
|
||||
/**
|
||||
* This method is a temporary method provided for easing migration from
|
||||
* suppliers to sources and sinks.
|
||||
*
|
||||
* @since 15.0
|
||||
* @deprecated This method is only provided for temporary compatibility with the
|
||||
* {@link InputSupplier} interface and should not be called
|
||||
* directly. Use {@link #openStream} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final InputStream getInput() throws IOException {
|
||||
return openStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new buffered {@link InputStream} for reading from this source. The
|
||||
* returned stream is not required to be a {@link BufferedInputStream} in order
|
||||
* to allow implementations to simply delegate to {@link #openStream()} when the
|
||||
* stream returned by that method does not benefit from additional buffering
|
||||
* (for example, a {@code ByteArrayInputStream}). This method should return a
|
||||
* new, independent stream each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned stream is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* stream
|
||||
* @since 15.0 (in 14.0 with return type {@link BufferedInputStream})
|
||||
*/
|
||||
public InputStream openBufferedStream() throws IOException {
|
||||
InputStream in = openStream();
|
||||
return (in instanceof BufferedInputStream) ? (BufferedInputStream) in : new BufferedInputStream(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of a slice of this byte source that is at most {@code length}
|
||||
* bytes long starting at the given {@code offset}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code offset} or {@code length} is
|
||||
* negative
|
||||
*/
|
||||
public ByteSource slice(long offset, long length) {
|
||||
return new SlicedByteSource(offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the source has zero bytes. The default implementation is to
|
||||
* open a stream and check for EOF.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @since 15.0
|
||||
*/
|
||||
public boolean isEmpty() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
return in.read() == -1;
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of this source in bytes. For most implementations, this is a
|
||||
* heavyweight operation that will open a stream, read (or
|
||||
* {@link InputStream#skip(long) skip}, if possible) to the end of the stream
|
||||
* and return the total number of bytes that were read.
|
||||
*
|
||||
* <p>
|
||||
* For some sources, such as a file, this method may use a more efficient
|
||||
* implementation. Note that in such cases, it is <i>possible</i> that this
|
||||
* method will return a different number of bytes than would be returned by
|
||||
* reading all of the bytes (for example, some special files may return a size
|
||||
* of 0 despite actually having content when read).
|
||||
*
|
||||
* <p>
|
||||
* In either case, if this is a mutable source such as a file, the size it
|
||||
* returns may not be the same number of bytes a subsequent read would return.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading the size
|
||||
* of this source
|
||||
*/
|
||||
public long size() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
return countBySkipping(in);
|
||||
} catch (IOException e) {
|
||||
// skip may not be supported... at any rate, try reading
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
|
||||
closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
return countByReading(in);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the bytes in the given input stream using skip if possible. Returns
|
||||
* SKIP_FAILED if the first call to skip threw, in which case skip may just not
|
||||
* be supported.
|
||||
*/
|
||||
private long countBySkipping(InputStream in) throws IOException {
|
||||
long count = 0;
|
||||
while (true) {
|
||||
// don't try to skip more than available()
|
||||
// things may work really wrong with FileInputStream otherwise
|
||||
long skipped = in.skip(Math.min(in.available(), Integer.MAX_VALUE));
|
||||
if (skipped <= 0) {
|
||||
if (in.read() == -1) {
|
||||
return count;
|
||||
} else if (count == 0 && in.available() == 0) {
|
||||
// if available is still zero after reading a single byte, it
|
||||
// will probably always be zero, so we should countByReading
|
||||
throw new IOException();
|
||||
}
|
||||
count++;
|
||||
} else {
|
||||
count += skipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] countBuffer = new byte[BUF_SIZE];
|
||||
|
||||
private long countByReading(InputStream in) throws IOException {
|
||||
long count = 0;
|
||||
long read;
|
||||
while ((read = in.read(countBuffer)) != -1) {
|
||||
count += read;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of this byte source to the given {@code OutputStream}.
|
||||
* Does not close {@code output}.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or writing to {@code output}
|
||||
*/
|
||||
public long copyTo(OutputStream output) throws IOException {
|
||||
checkNotNull(output);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
return ByteStreams.copy(in, output);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of this byte source to the given {@code ByteSink}.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or writing to {@code sink}
|
||||
*/
|
||||
public long copyTo(ByteSink sink) throws IOException {
|
||||
checkNotNull(sink);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
OutputStream out = closer.register(sink.openStream());
|
||||
return ByteStreams.copy(in, out);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the full contents of this byte source as a byte array.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source
|
||||
*/
|
||||
public byte[] read() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
return ByteStreams.toByteArray(in);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of this byte source using the given {@code processor} to
|
||||
* process bytes as they are read. Stops when all bytes have been read or the
|
||||
* consumer returns {@code false}. Returns the result produced by the processor.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or if {@code processor} throws an
|
||||
* {@code IOException}
|
||||
* @since 16.0
|
||||
*/
|
||||
@Beta
|
||||
public <T> T read(ByteProcessor<T> processor) throws IOException {
|
||||
checkNotNull(processor);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in = closer.register(openStream());
|
||||
return ByteStreams.readBytes(in, processor);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes the contents of this byte source using the given hash function.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source
|
||||
*/
|
||||
public HashCode hash(HashFunction hashFunction) throws IOException {
|
||||
Hasher hasher = hashFunction.newHasher();
|
||||
copyTo(Funnels.asOutputStream(hasher));
|
||||
return hasher.hash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the contents of this byte source are equal to the contents of the
|
||||
* given byte source.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or {@code other}
|
||||
*/
|
||||
public boolean contentEquals(ByteSource other) throws IOException {
|
||||
checkNotNull(other);
|
||||
|
||||
byte[] buf1 = new byte[BUF_SIZE];
|
||||
byte[] buf2 = new byte[BUF_SIZE];
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
InputStream in1 = closer.register(openStream());
|
||||
InputStream in2 = closer.register(other.openStream());
|
||||
while (true) {
|
||||
int read1 = ByteStreams.read(in1, buf1, 0, BUF_SIZE);
|
||||
int read2 = ByteStreams.read(in2, buf2, 0, BUF_SIZE);
|
||||
if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
|
||||
return false;
|
||||
} else if (read1 != BUF_SIZE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates multiple {@link ByteSource} instances into a single source.
|
||||
* Streams returned from the source will contain the concatenated data from the
|
||||
* streams of the underlying sources.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying stream will be open at a time. Closing the concatenated
|
||||
* stream will close the open underlying stream.
|
||||
*
|
||||
* @param sources the sources to concatenate
|
||||
* @return a {@code ByteSource} containing the concatenated data
|
||||
* @since 15.0
|
||||
*/
|
||||
public static ByteSource concat(Iterable<? extends ByteSource> sources) {
|
||||
return new ConcatenatedByteSource(sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates multiple {@link ByteSource} instances into a single source.
|
||||
* Streams returned from the source will contain the concatenated data from the
|
||||
* streams of the underlying sources.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying stream will be open at a time. Closing the concatenated
|
||||
* stream will close the open underlying stream.
|
||||
*
|
||||
* <p>
|
||||
* Note: The input {@code Iterator} will be copied to an {@code ImmutableList}
|
||||
* when this method is called. This will fail if the iterator is infinite and
|
||||
* may cause problems if the iterator eagerly fetches data for each source when
|
||||
* iterated (rather than producing sources that only load data through their
|
||||
* streams). Prefer using the {@link #concat(Iterable)} overload if possible.
|
||||
*
|
||||
* @param sources the sources to concatenate
|
||||
* @return a {@code ByteSource} containing the concatenated data
|
||||
* @throws NullPointerException if any of {@code sources} is {@code null}
|
||||
* @since 15.0
|
||||
*/
|
||||
public static ByteSource concat(Iterator<? extends ByteSource> sources) {
|
||||
return concat(ImmutableList.copyOf(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates multiple {@link ByteSource} instances into a single source.
|
||||
* Streams returned from the source will contain the concatenated data from the
|
||||
* streams of the underlying sources.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying stream will be open at a time. Closing the concatenated
|
||||
* stream will close the open underlying stream.
|
||||
*
|
||||
* @param sources the sources to concatenate
|
||||
* @return a {@code ByteSource} containing the concatenated data
|
||||
* @throws NullPointerException if any of {@code sources} is {@code null}
|
||||
* @since 15.0
|
||||
*/
|
||||
public static ByteSource concat(ByteSource... sources) {
|
||||
return concat(ImmutableList.copyOf(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of the given byte array as a {@link ByteSource}. To view only
|
||||
* a specific range in the array, use
|
||||
* {@code ByteSource.wrap(b).slice(offset, length)}.
|
||||
*
|
||||
* @since 15.0 (since 14.0 as {@code ByteStreams.asByteSource(byte[])}).
|
||||
*/
|
||||
public static ByteSource wrap(byte[] b) {
|
||||
return new ByteArrayByteSource(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable {@link ByteSource} that contains no bytes.
|
||||
*
|
||||
* @since 15.0
|
||||
*/
|
||||
public static ByteSource empty() {
|
||||
return EmptyByteSource.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* A char source that reads bytes from this source and decodes them as
|
||||
* characters using a charset.
|
||||
*/
|
||||
private final class AsCharSource extends CharSource {
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
private AsCharSource(Charset charset) {
|
||||
this.charset = checkNotNull(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader openStream() throws IOException {
|
||||
return new InputStreamReader(ByteSource.this.openStream(), charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ByteSource.this.toString() + ".asCharSource(" + charset + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A view of a subsection of the containing byte source.
|
||||
*/
|
||||
private final class SlicedByteSource extends ByteSource {
|
||||
|
||||
private final long offset;
|
||||
private final long length;
|
||||
|
||||
private SlicedByteSource(long offset, long length) {
|
||||
checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
|
||||
checkArgument(length >= 0, "length (%s) may not be negative", length);
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openStream() throws IOException {
|
||||
return sliceStream(ByteSource.this.openStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openBufferedStream() throws IOException {
|
||||
return sliceStream(ByteSource.this.openBufferedStream());
|
||||
}
|
||||
|
||||
private InputStream sliceStream(InputStream in) throws IOException {
|
||||
if (offset > 0) {
|
||||
try {
|
||||
ByteStreams.skipFully(in, offset);
|
||||
} catch (Throwable e) {
|
||||
Closer closer = Closer.create();
|
||||
closer.register(in);
|
||||
try {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ByteStreams.limit(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteSource slice(long offset, long length) {
|
||||
checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
|
||||
checkArgument(length >= 0, "length (%s) may not be negative", length);
|
||||
long maxLength = this.length - offset;
|
||||
return ByteSource.this.slice(this.offset + offset, Math.min(length, maxLength));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() throws IOException {
|
||||
return length == 0 || super.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ByteSource.this.toString() + ".slice(" + offset + ", " + length + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static class ByteArrayByteSource extends ByteSource {
|
||||
|
||||
protected final byte[] bytes;
|
||||
|
||||
protected ByteArrayByteSource(byte[] bytes) {
|
||||
this.bytes = checkNotNull(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openStream() {
|
||||
return new EaglerInputStream(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openBufferedStream() throws IOException {
|
||||
return openStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return bytes.length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read() {
|
||||
return bytes.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long copyTo(OutputStream output) throws IOException {
|
||||
output.write(bytes);
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T read(ByteProcessor<T> processor) throws IOException {
|
||||
processor.processBytes(bytes, 0, bytes.length);
|
||||
return processor.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashCode hash(HashFunction hashFunction) throws IOException {
|
||||
return hashFunction.hashBytes(bytes);
|
||||
}
|
||||
|
||||
// TODO(user): Possibly override slice()
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ByteSource.wrap(" + Ascii.truncate(BaseEncoding.base16().encode(bytes), 30, "...") + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class EmptyByteSource extends ByteArrayByteSource {
|
||||
|
||||
private static final EmptyByteSource INSTANCE = new EmptyByteSource();
|
||||
|
||||
private EmptyByteSource() {
|
||||
super(new byte[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSource asCharSource(Charset charset) {
|
||||
checkNotNull(charset);
|
||||
return CharSource.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read() {
|
||||
return bytes; // length is 0, no need to clone
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ByteSource.empty()";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConcatenatedByteSource extends ByteSource {
|
||||
|
||||
private final Iterable<? extends ByteSource> sources;
|
||||
|
||||
ConcatenatedByteSource(Iterable<? extends ByteSource> sources) {
|
||||
this.sources = checkNotNull(sources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openStream() throws IOException {
|
||||
return new MultiInputStream(sources.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() throws IOException {
|
||||
for (ByteSource source : sources) {
|
||||
if (!source.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() throws IOException {
|
||||
long result = 0L;
|
||||
for (ByteSource source : sources) {
|
||||
result += source.size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ByteSource.concat(" + sources + ")";
|
||||
}
|
||||
}
|
||||
}
|
1091
sources/main/java/com/google/common/io/ByteStreams.java
Normal file
1091
sources/main/java/com/google/common/io/ByteStreams.java
Normal file
File diff suppressed because it is too large
Load Diff
132
sources/main/java/com/google/common/io/CharSequenceReader.java
Normal file
132
sources/main/java/com/google/common/io/CharSequenceReader.java
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkPositionIndexes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
/**
|
||||
* A {@link Reader} that reads the characters in a {@link CharSequence}. Like
|
||||
* {@code StringReader}, but works with any {@link CharSequence}.
|
||||
*
|
||||
* @author Colin Decker
|
||||
*/
|
||||
// TODO(user): make this public? as a type, or a method in CharStreams?
|
||||
final class CharSequenceReader extends Reader {
|
||||
|
||||
private CharSequence seq;
|
||||
private int pos;
|
||||
private int mark;
|
||||
|
||||
/**
|
||||
* Creates a new reader wrapping the given character sequence.
|
||||
*/
|
||||
public CharSequenceReader(CharSequence seq) {
|
||||
this.seq = checkNotNull(seq);
|
||||
}
|
||||
|
||||
private void checkOpen() throws IOException {
|
||||
if (seq == null) {
|
||||
throw new IOException("reader closed");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRemaining() {
|
||||
return remaining() > 0;
|
||||
}
|
||||
|
||||
private int remaining() {
|
||||
return seq.length() - pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read(CharBuffer target) throws IOException {
|
||||
checkNotNull(target);
|
||||
checkOpen();
|
||||
if (!hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
int charsToRead = Math.min(target.remaining(), remaining());
|
||||
for (int i = 0; i < charsToRead; i++) {
|
||||
target.put(seq.charAt(pos++));
|
||||
}
|
||||
return charsToRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read() throws IOException {
|
||||
checkOpen();
|
||||
return hasRemaining() ? seq.charAt(pos++) : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read(char[] cbuf, int off, int len) throws IOException {
|
||||
checkPositionIndexes(off, off + len, cbuf.length);
|
||||
checkOpen();
|
||||
if (!hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
int charsToRead = Math.min(len, remaining());
|
||||
for (int i = 0; i < charsToRead; i++) {
|
||||
cbuf[off + i] = seq.charAt(pos++);
|
||||
}
|
||||
return charsToRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long skip(long n) throws IOException {
|
||||
checkArgument(n >= 0, "n (%s) may not be negative", n);
|
||||
checkOpen();
|
||||
int charsToSkip = (int) Math.min(remaining(), n); // safe because remaining is an int
|
||||
pos += charsToSkip;
|
||||
return charsToSkip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean ready() throws IOException {
|
||||
checkOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readAheadLimit) throws IOException {
|
||||
checkArgument(readAheadLimit >= 0, "readAheadLimit (%s) may not be negative", readAheadLimit);
|
||||
checkOpen();
|
||||
mark = pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
checkOpen();
|
||||
pos = mark;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
seq = null;
|
||||
}
|
||||
}
|
190
sources/main/java/com/google/common/io/CharSink.java
Normal file
190
sources/main/java/com/google/common/io/CharSink.java
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* A destination to which characters can be written, such as a text file. Unlike
|
||||
* a {@link Writer}, a {@code CharSink} is not an open, stateful stream that can
|
||||
* be written to and closed. Instead, it is an immutable <i>supplier</i> of
|
||||
* {@code Writer} instances.
|
||||
*
|
||||
* <p>
|
||||
* {@code CharSink} provides two kinds of methods:
|
||||
* <ul>
|
||||
* <li><b>Methods that return a writer:</b> These methods should return a
|
||||
* <i>new</i>, independent instance each time they are called. The caller is
|
||||
* responsible for ensuring that the returned writer is closed.
|
||||
* <li><b>Convenience methods:</b> These are implementations of common
|
||||
* operations that are typically implemented by opening a writer using one of
|
||||
* the methods in the first category, doing something and finally closing the
|
||||
* writer that was opened.
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Any {@link ByteSink} may be viewed as a {@code CharSink} with a specific
|
||||
* {@linkplain Charset character encoding} using
|
||||
* {@link ByteSink#asCharSink(Charset)}. Characters written to the resulting
|
||||
* {@code CharSink} will written to the {@code ByteSink} as encoded bytes.
|
||||
*
|
||||
* @since 14.0
|
||||
* @author Colin Decker
|
||||
*/
|
||||
public abstract class CharSink implements OutputSupplier<Writer> {
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses.
|
||||
*/
|
||||
protected CharSink() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new {@link Writer} for writing to this sink. This method should
|
||||
* return a new, independent writer each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned writer is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* writer
|
||||
*/
|
||||
public abstract Writer openStream() throws IOException;
|
||||
|
||||
/**
|
||||
* This method is a temporary method provided for easing migration from
|
||||
* suppliers to sources and sinks.
|
||||
*
|
||||
* @since 15.0
|
||||
* @deprecated This method is only provided for temporary compatibility with the
|
||||
* {@link OutputSupplier} interface and should not be called
|
||||
* directly. Use {@link #openStream} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final Writer getOutput() throws IOException {
|
||||
return openStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new buffered {@link Writer} for writing to this sink. The returned
|
||||
* stream is not required to be a {@link BufferedWriter} in order to allow
|
||||
* implementations to simply delegate to {@link #openStream()} when the stream
|
||||
* returned by that method does not benefit from additional buffering. This
|
||||
* method should return a new, independent writer each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned writer is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* writer
|
||||
* @since 15.0 (in 14.0 with return type {@link BufferedWriter})
|
||||
*/
|
||||
public Writer openBufferedStream() throws IOException {
|
||||
Writer writer = openStream();
|
||||
return (writer instanceof BufferedWriter) ? (BufferedWriter) writer : new BufferedWriter(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given character sequence to this sink.
|
||||
*
|
||||
* @throws IOException if an I/O error in the process of writing to this sink
|
||||
*/
|
||||
public void write(CharSequence charSequence) throws IOException {
|
||||
checkNotNull(charSequence);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Writer out = closer.register(openStream());
|
||||
out.append(charSequence);
|
||||
out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given lines of text to this sink with each line (including the
|
||||
* last) terminated with the operating system's default line separator. This
|
||||
* method is equivalent to
|
||||
* {@code writeLines(lines, System.getProperty("line.separator"))}.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of writing to this
|
||||
* sink
|
||||
*/
|
||||
public void writeLines(Iterable<? extends CharSequence> lines) throws IOException {
|
||||
writeLines(lines, System.getProperty("line.separator"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given lines of text to this sink with each line (including the
|
||||
* last) terminated with the given line separator.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of writing to this
|
||||
* sink
|
||||
*/
|
||||
public void writeLines(Iterable<? extends CharSequence> lines, String lineSeparator) throws IOException {
|
||||
checkNotNull(lines);
|
||||
checkNotNull(lineSeparator);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Writer out = closer.register(openBufferedStream());
|
||||
for (CharSequence line : lines) {
|
||||
out.append(line).append(lineSeparator);
|
||||
}
|
||||
out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all the text from the given {@link Readable} (such as a
|
||||
* {@link Reader}) to this sink. Does not close {@code readable} if it is
|
||||
* {@code Closeable}.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* {@code readable} or writing to this sink
|
||||
*/
|
||||
public long writeFrom(Readable readable) throws IOException {
|
||||
checkNotNull(readable);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Writer out = closer.register(openStream());
|
||||
long written = CharStreams.copy(readable, out);
|
||||
out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
|
||||
return written;
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
}
|
493
sources/main/java/com/google/common/io/CharSource.java
Normal file
493
sources/main/java/com/google/common/io/CharSource.java
Normal file
@ -0,0 +1,493 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* A readable source of characters, such as a text file. Unlike a
|
||||
* {@link Reader}, a {@code CharSource} is not an open, stateful stream of
|
||||
* characters that can be read and closed. Instead, it is an immutable
|
||||
* <i>supplier</i> of {@code Reader} instances.
|
||||
*
|
||||
* <p>
|
||||
* {@code CharSource} provides two kinds of methods:
|
||||
* <ul>
|
||||
* <li><b>Methods that return a reader:</b> These methods should return a
|
||||
* <i>new</i>, independent instance each time they are called. The caller is
|
||||
* responsible for ensuring that the returned reader is closed.
|
||||
* <li><b>Convenience methods:</b> These are implementations of common
|
||||
* operations that are typically implemented by opening a reader using one of
|
||||
* the methods in the first category, doing something and finally closing the
|
||||
* reader that was opened.
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Several methods in this class, such as {@link #readLines()}, break the
|
||||
* contents of the source into lines. Like {@link BufferedReader}, these methods
|
||||
* break lines on any of {@code \n}, {@code \r} or {@code \r\n}, do not include
|
||||
* the line separator in each line and do not consider there to be an empty line
|
||||
* at the end if the contents are terminated with a line separator.
|
||||
*
|
||||
* <p>
|
||||
* Any {@link ByteSource} containing text encoded with a specific
|
||||
* {@linkplain Charset character encoding} may be viewed as a {@code CharSource}
|
||||
* using {@link ByteSource#asCharSource(Charset)}.
|
||||
*
|
||||
* @since 14.0
|
||||
* @author Colin Decker
|
||||
*/
|
||||
public abstract class CharSource implements InputSupplier<Reader> {
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses.
|
||||
*/
|
||||
protected CharSource() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new {@link Reader} for reading from this source. This method should
|
||||
* return a new, independent reader each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned reader is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* reader
|
||||
*/
|
||||
public abstract Reader openStream() throws IOException;
|
||||
|
||||
/**
|
||||
* This method is a temporary method provided for easing migration from
|
||||
* suppliers to sources and sinks.
|
||||
*
|
||||
* @since 15.0
|
||||
* @deprecated This method is only provided for temporary compatibility with the
|
||||
* {@link InputSupplier} interface and should not be called
|
||||
* directly. Use {@link #openStream} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final Reader getInput() throws IOException {
|
||||
return openStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new {@link BufferedReader} for reading from this source. This method
|
||||
* should return a new, independent reader each time it is called.
|
||||
*
|
||||
* <p>
|
||||
* The caller is responsible for ensuring that the returned reader is closed.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of opening the
|
||||
* reader
|
||||
*/
|
||||
public BufferedReader openBufferedStream() throws IOException {
|
||||
Reader reader = openStream();
|
||||
return (reader instanceof BufferedReader) ? (BufferedReader) reader : new BufferedReader(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the contents of this source to the given {@link Appendable} (such as
|
||||
* a {@link Writer}). Does not close {@code appendable} if it is
|
||||
* {@code Closeable}.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or writing to {@code appendable}
|
||||
*/
|
||||
public long copyTo(Appendable appendable) throws IOException {
|
||||
checkNotNull(appendable);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Reader reader = closer.register(openStream());
|
||||
return CharStreams.copy(reader, appendable);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of this source to the given sink.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or writing to {@code sink}
|
||||
*/
|
||||
public long copyTo(CharSink sink) throws IOException {
|
||||
checkNotNull(sink);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Reader reader = closer.register(openStream());
|
||||
Writer writer = closer.register(sink.openStream());
|
||||
return CharStreams.copy(reader, writer);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of this source as a string.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source
|
||||
*/
|
||||
public String read() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Reader reader = closer.register(openStream());
|
||||
return CharStreams.toString(reader);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the first link of this source as a string. Returns {@code null} if this
|
||||
* source is empty.
|
||||
*
|
||||
* <p>
|
||||
* Like {@link BufferedReader}, this method breaks lines on any of {@code \n},
|
||||
* {@code \r} or {@code \r\n}, does not include the line separator in the
|
||||
* returned line and does not consider there to be an extra empty line at the
|
||||
* end if the content is terminated with a line separator.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source
|
||||
*/
|
||||
public @Nullable String readFirstLine() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
BufferedReader reader = closer.register(openBufferedStream());
|
||||
return reader.readLine();
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the lines of this source as a list of strings. The returned list
|
||||
* will be empty if this source is empty.
|
||||
*
|
||||
* <p>
|
||||
* Like {@link BufferedReader}, this method breaks lines on any of {@code \n},
|
||||
* {@code \r} or {@code \r\n}, does not include the line separator in the
|
||||
* returned lines and does not consider there to be an extra empty line at the
|
||||
* end if the content is terminated with a line separator.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source
|
||||
*/
|
||||
public ImmutableList<String> readLines() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
BufferedReader reader = closer.register(openBufferedStream());
|
||||
List<String> result = Lists.newArrayList();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
result.add(line);
|
||||
}
|
||||
return ImmutableList.copyOf(result);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads lines of text from this source, processing each line as it is read
|
||||
* using the given {@link LineProcessor processor}. Stops when all lines have
|
||||
* been processed or the processor returns {@code false} and returns the result
|
||||
* produced by the processor.
|
||||
*
|
||||
* <p>
|
||||
* Like {@link BufferedReader}, this method breaks lines on any of {@code \n},
|
||||
* {@code \r} or {@code \r\n}, does not include the line separator in the lines
|
||||
* passed to the {@code processor} and does not consider there to be an extra
|
||||
* empty line at the end if the content is terminated with a line separator.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs in the process of reading from
|
||||
* this source or if {@code processor} throws an
|
||||
* {@code IOException}
|
||||
* @since 16.0
|
||||
*/
|
||||
@Beta
|
||||
public <T> T readLines(LineProcessor<T> processor) throws IOException {
|
||||
checkNotNull(processor);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Reader reader = closer.register(openStream());
|
||||
return CharStreams.readLines(reader, processor);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the source has zero chars. The default implementation is to
|
||||
* open a stream and check for EOF.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @since 15.0
|
||||
*/
|
||||
public boolean isEmpty() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
Reader reader = closer.register(openStream());
|
||||
return reader.read() == -1;
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates multiple {@link CharSource} instances into a single source.
|
||||
* Streams returned from the source will contain the concatenated data from the
|
||||
* streams of the underlying sources.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying stream will be open at a time. Closing the concatenated
|
||||
* stream will close the open underlying stream.
|
||||
*
|
||||
* @param sources the sources to concatenate
|
||||
* @return a {@code CharSource} containing the concatenated data
|
||||
* @since 15.0
|
||||
*/
|
||||
public static CharSource concat(Iterable<? extends CharSource> sources) {
|
||||
return new ConcatenatedCharSource(sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates multiple {@link CharSource} instances into a single source.
|
||||
* Streams returned from the source will contain the concatenated data from the
|
||||
* streams of the underlying sources.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying stream will be open at a time. Closing the concatenated
|
||||
* stream will close the open underlying stream.
|
||||
*
|
||||
* <p>
|
||||
* Note: The input {@code Iterator} will be copied to an {@code ImmutableList}
|
||||
* when this method is called. This will fail if the iterator is infinite and
|
||||
* may cause problems if the iterator eagerly fetches data for each source when
|
||||
* iterated (rather than producing sources that only load data through their
|
||||
* streams). Prefer using the {@link #concat(Iterable)} overload if possible.
|
||||
*
|
||||
* @param sources the sources to concatenate
|
||||
* @return a {@code CharSource} containing the concatenated data
|
||||
* @throws NullPointerException if any of {@code sources} is {@code null}
|
||||
* @since 15.0
|
||||
*/
|
||||
public static CharSource concat(Iterator<? extends CharSource> sources) {
|
||||
return concat(ImmutableList.copyOf(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates multiple {@link CharSource} instances into a single source.
|
||||
* Streams returned from the source will contain the concatenated data from the
|
||||
* streams of the underlying sources.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying stream will be open at a time. Closing the concatenated
|
||||
* stream will close the open underlying stream.
|
||||
*
|
||||
* @param sources the sources to concatenate
|
||||
* @return a {@code CharSource} containing the concatenated data
|
||||
* @throws NullPointerException if any of {@code sources} is {@code null}
|
||||
* @since 15.0
|
||||
*/
|
||||
public static CharSource concat(CharSource... sources) {
|
||||
return concat(ImmutableList.copyOf(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of the given character sequence as a {@link CharSource}. The
|
||||
* behavior of the returned {@code CharSource} and any {@code Reader} instances
|
||||
* created by it is unspecified if the {@code charSequence} is mutated while it
|
||||
* is being read, so don't do that.
|
||||
*
|
||||
* @since 15.0 (since 14.0 as {@code CharStreams.asCharSource(String)})
|
||||
*/
|
||||
public static CharSource wrap(CharSequence charSequence) {
|
||||
return new CharSequenceCharSource(charSequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable {@link CharSource} that contains no characters.
|
||||
*
|
||||
* @since 15.0
|
||||
*/
|
||||
public static CharSource empty() {
|
||||
return EmptyCharSource.INSTANCE;
|
||||
}
|
||||
|
||||
private static class CharSequenceCharSource extends CharSource {
|
||||
|
||||
private static final Splitter LINE_SPLITTER = Splitter.on(Pattern.compile("\r\n|\n|\r"));
|
||||
|
||||
private final CharSequence seq;
|
||||
|
||||
protected CharSequenceCharSource(CharSequence seq) {
|
||||
this.seq = checkNotNull(seq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader openStream() {
|
||||
return new CharSequenceReader(seq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read() {
|
||||
return seq.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return seq.length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable over the lines in the string. If the string ends in a
|
||||
* newline, a final empty string is not included to match the behavior of
|
||||
* BufferedReader/LineReader.readLine().
|
||||
*/
|
||||
private Iterable<String> lines() {
|
||||
return new Iterable<String>() {
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return new AbstractIterator<String>() {
|
||||
Iterator<String> lines = LINE_SPLITTER.split(seq).iterator();
|
||||
|
||||
@Override
|
||||
protected String computeNext() {
|
||||
if (lines.hasNext()) {
|
||||
String next = lines.next();
|
||||
// skip last line if it's empty
|
||||
if (lines.hasNext() || !next.isEmpty()) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readFirstLine() {
|
||||
Iterator<String> lines = lines().iterator();
|
||||
return lines.hasNext() ? lines.next() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> readLines() {
|
||||
return ImmutableList.copyOf(lines());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T readLines(LineProcessor<T> processor) throws IOException {
|
||||
for (String line : lines()) {
|
||||
if (!processor.processLine(line)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return processor.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharSource.wrap(" + Ascii.truncate(seq, 30, "...") + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class EmptyCharSource extends CharSequenceCharSource {
|
||||
|
||||
private static final EmptyCharSource INSTANCE = new EmptyCharSource();
|
||||
|
||||
private EmptyCharSource() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharSource.empty()";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConcatenatedCharSource extends CharSource {
|
||||
|
||||
private final Iterable<? extends CharSource> sources;
|
||||
|
||||
ConcatenatedCharSource(Iterable<? extends CharSource> sources) {
|
||||
this.sources = checkNotNull(sources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader openStream() throws IOException {
|
||||
return new MultiReader(sources.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() throws IOException {
|
||||
for (CharSource source : sources) {
|
||||
if (!source.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharSource.concat(" + sources + ")";
|
||||
}
|
||||
}
|
||||
}
|
597
sources/main/java/com/google/common/io/CharStreams.java
Normal file
597
sources/main/java/com/google/common/io/CharStreams.java
Normal file
@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkPositionIndexes;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.Writer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Provides utility methods for working with character streams.
|
||||
*
|
||||
* <p>
|
||||
* All method parameters must be non-null unless documented otherwise.
|
||||
*
|
||||
* <p>
|
||||
* Some of the methods in this class take arguments with a generic type of
|
||||
* {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
|
||||
* those interfaces. Similarly for {@code Appendable & Closeable} and
|
||||
* {@link java.io.Writer}.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Bin Zhu
|
||||
* @author Colin Decker
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class CharStreams {
|
||||
private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
|
||||
|
||||
private CharStreams() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory that will supply instances of {@link StringReader} that
|
||||
* read a string value.
|
||||
*
|
||||
* @param value the string to read
|
||||
* @return the factory
|
||||
* @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static InputSupplier<StringReader> newReaderSupplier(final String value) {
|
||||
return asInputSupplier(CharSource.wrap(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory that will supply instances of {@link InputStreamReader},
|
||||
* using the given {@link InputStream} factory and character set.
|
||||
*
|
||||
* @param in the factory that will be used to open input streams
|
||||
* @param charset the charset used to decode the input stream; see
|
||||
* {@link Charsets} for helpful predefined constants
|
||||
* @return the factory
|
||||
* @deprecated Use {@link ByteSource#asCharSource(Charset)} instead. This method
|
||||
* is scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static InputSupplier<InputStreamReader> newReaderSupplier(final InputSupplier<? extends InputStream> in,
|
||||
final Charset charset) {
|
||||
return asInputSupplier(ByteStreams.asByteSource(in).asCharSource(charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory that will supply instances of {@link OutputStreamWriter},
|
||||
* using the given {@link OutputStream} factory and character set.
|
||||
*
|
||||
* @param out the factory that will be used to open output streams
|
||||
* @param charset the charset used to encode the output stream; see
|
||||
* {@link Charsets} for helpful predefined constants
|
||||
* @return the factory
|
||||
* @deprecated Use {@link ByteSink#asCharSink(Charset)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static OutputSupplier<OutputStreamWriter> newWriterSupplier(final OutputSupplier<? extends OutputStream> out,
|
||||
final Charset charset) {
|
||||
return asOutputSupplier(ByteStreams.asByteSink(out).asCharSink(charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character sequence (such as a string) to an appendable object from
|
||||
* the given supplier.
|
||||
*
|
||||
* @param from the character sequence to write
|
||||
* @param to the output supplier
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSink#write(CharSequence)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <W extends Appendable & Closeable> void write(CharSequence from, OutputSupplier<W> to)
|
||||
throws IOException {
|
||||
asCharSink(to).write(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens {@link Readable} and {@link Appendable} objects from the given
|
||||
* factories, copies all characters between the two, and closes them.
|
||||
*
|
||||
* @param from the input factory
|
||||
* @param to the output factory
|
||||
* @return the number of characters copied
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSource#copyTo(CharSink)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <R extends Readable & Closeable, W extends Appendable & Closeable> long copy(InputSupplier<R> from,
|
||||
OutputSupplier<W> to) throws IOException {
|
||||
return asCharSource(from).copyTo(asCharSink(to));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a {@link Readable} object from the supplier, copies all characters to
|
||||
* the {@link Appendable} object, and closes the input. Does not close or flush
|
||||
* the output.
|
||||
*
|
||||
* @param from the input factory
|
||||
* @param to the object to write to
|
||||
* @return the number of characters copied
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSource#copyTo(Appendable)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <R extends Readable & Closeable> long copy(InputSupplier<R> from, Appendable to) throws IOException {
|
||||
return asCharSource(from).copyTo(to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all characters between the {@link Readable} and {@link Appendable}
|
||||
* objects. Does not close or flush either object.
|
||||
*
|
||||
* @param from the object to read from
|
||||
* @param to the object to write to
|
||||
* @return the number of characters copied
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static long copy(Readable from, Appendable to) throws IOException {
|
||||
checkNotNull(from);
|
||||
checkNotNull(to);
|
||||
CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
|
||||
long total = 0;
|
||||
while (from.read(buf) != -1) {
|
||||
buf.flip();
|
||||
to.append(buf);
|
||||
total += buf.remaining();
|
||||
buf.clear();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all characters from a {@link Readable} object into a {@link String}.
|
||||
* Does not close the {@code Readable}.
|
||||
*
|
||||
* @param r the object to read from
|
||||
* @return a string containing all the characters
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static String toString(Readable r) throws IOException {
|
||||
return toStringBuilder(r).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the characters from a {@link Readable} & {@link Closeable} object
|
||||
* supplied by a factory as a {@link String}.
|
||||
*
|
||||
* @param supplier the factory to read from
|
||||
* @return a string containing all the characters
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSource#read()} instead. This method is scheduled
|
||||
* for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <R extends Readable & Closeable> String toString(InputSupplier<R> supplier) throws IOException {
|
||||
return asCharSource(supplier).read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all characters from a {@link Readable} object into a new
|
||||
* {@link StringBuilder} instance. Does not close the {@code Readable}.
|
||||
*
|
||||
* @param r the object to read from
|
||||
* @return a {@link StringBuilder} containing all the characters
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private static StringBuilder toStringBuilder(Readable r) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
copy(r, sb);
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the first line from a {@link Readable} & {@link Closeable} object
|
||||
* supplied by a factory. The line does not include line-termination characters,
|
||||
* but does include other leading and trailing whitespace.
|
||||
*
|
||||
* @param supplier the factory to read from
|
||||
* @return the first line, or null if the reader is empty
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSource#readFirstLine()} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <R extends Readable & Closeable> String readFirstLine(InputSupplier<R> supplier) throws IOException {
|
||||
return asCharSource(supplier).readFirstLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all of the lines from a {@link Readable} & {@link Closeable} object
|
||||
* supplied by a factory. The lines do not include line-termination characters,
|
||||
* but do include other leading and trailing whitespace.
|
||||
*
|
||||
* @param supplier the factory to read from
|
||||
* @return a mutable {@link List} containing all the lines
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSource#readLines()} instead, but note that it
|
||||
* returns an {@code ImmutableList}. This method is scheduled for
|
||||
* removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <R extends Readable & Closeable> List<String> readLines(InputSupplier<R> supplier)
|
||||
throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
R r = closer.register(supplier.getInput());
|
||||
return readLines(r);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all of the lines from a {@link Readable} object. The lines do not
|
||||
* include line-termination characters, but do include other leading and
|
||||
* trailing whitespace.
|
||||
*
|
||||
* <p>
|
||||
* Does not close the {@code Readable}. If reading files or resources you should
|
||||
* use the {@link Files#readLines} and {@link Resources#readLines} methods.
|
||||
*
|
||||
* @param r the object to read from
|
||||
* @return a mutable {@link List} containing all the lines
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static List<String> readLines(Readable r) throws IOException {
|
||||
List<String> result = new ArrayList<String>();
|
||||
LineReader lineReader = new LineReader(r);
|
||||
String line;
|
||||
while ((line = lineReader.readLine()) != null) {
|
||||
result.add(line);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams lines from a {@link Readable} object, stopping when the processor
|
||||
* returns {@code false} or all lines have been read and returning the result
|
||||
* produced by the processor. Does not close {@code readable}. Note that this
|
||||
* method may not fully consume the contents of {@code readable} if the
|
||||
* processor stops processing early.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @since 14.0
|
||||
*/
|
||||
public static <T> T readLines(Readable readable, LineProcessor<T> processor) throws IOException {
|
||||
checkNotNull(readable);
|
||||
checkNotNull(processor);
|
||||
|
||||
LineReader lineReader = new LineReader(readable);
|
||||
String line;
|
||||
while ((line = lineReader.readLine()) != null) {
|
||||
if (!processor.processLine(line)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return processor.getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams lines from a {@link Readable} and {@link Closeable} object supplied
|
||||
* by a factory, stopping when our callback returns false, or we have read all
|
||||
* of the lines.
|
||||
*
|
||||
* @param supplier the factory to read from
|
||||
* @param callback the LineProcessor to use to handle the lines
|
||||
* @return the output of processing the lines
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @deprecated Use {@link CharSource#readLines(LineProcessor)} instead. This
|
||||
* method is scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <R extends Readable & Closeable, T> T readLines(InputSupplier<R> supplier, LineProcessor<T> callback)
|
||||
throws IOException {
|
||||
checkNotNull(supplier);
|
||||
checkNotNull(callback);
|
||||
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
R r = closer.register(supplier.getInput());
|
||||
return readLines(r, callback);
|
||||
} catch (Throwable e) {
|
||||
throw closer.rethrow(e);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins multiple {@link Reader} suppliers into a single supplier. Reader
|
||||
* returned from the supplier will contain the concatenated data from the
|
||||
* readers of the underlying suppliers.
|
||||
*
|
||||
* <p>
|
||||
* Reading from the joined reader will throw a {@link NullPointerException} if
|
||||
* any of the suppliers are null or return null.
|
||||
*
|
||||
* <p>
|
||||
* Only one underlying reader will be open at a time. Closing the joined reader
|
||||
* will close the open underlying reader.
|
||||
*
|
||||
* @param suppliers the suppliers to concatenate
|
||||
* @return a supplier that will return a reader containing the concatenated data
|
||||
* @deprecated Use {@link CharSource#concat(Iterable)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static InputSupplier<Reader> join(final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
|
||||
checkNotNull(suppliers);
|
||||
Iterable<CharSource> sources = Iterables.transform(suppliers,
|
||||
new Function<InputSupplier<? extends Reader>, CharSource>() {
|
||||
@Override
|
||||
public CharSource apply(InputSupplier<? extends Reader> input) {
|
||||
return asCharSource(input);
|
||||
}
|
||||
});
|
||||
return asInputSupplier(CharSource.concat(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Varargs form of {@link #join(Iterable)}.
|
||||
*
|
||||
* @deprecated Use {@link CharSource#concat(CharSource[])} instead. This method
|
||||
* is scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked") // suppress "possible heap pollution" warning in JDK7
|
||||
public static InputSupplier<Reader> join(InputSupplier<? extends Reader>... suppliers) {
|
||||
return join(Arrays.asList(suppliers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards {@code n} characters of data from the reader. This method will block
|
||||
* until the full amount has been skipped. Does not close the reader.
|
||||
*
|
||||
* @param reader the reader to read from
|
||||
* @param n the number of characters to skip
|
||||
* @throws EOFException if this stream reaches the end before skipping all the
|
||||
* characters
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void skipFully(Reader reader, long n) throws IOException {
|
||||
checkNotNull(reader);
|
||||
while (n > 0) {
|
||||
long amt = reader.skip(n);
|
||||
if (amt == 0) {
|
||||
// force a blocking read
|
||||
if (reader.read() == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
n--;
|
||||
} else {
|
||||
n -= amt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Writer} that simply discards written chars.
|
||||
*
|
||||
* @since 15.0
|
||||
*/
|
||||
public static Writer nullWriter() {
|
||||
return NullWriter.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class NullWriter extends Writer {
|
||||
|
||||
private static final NullWriter INSTANCE = new NullWriter();
|
||||
|
||||
@Override
|
||||
public void write(int c) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] cbuf) {
|
||||
checkNotNull(cbuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) {
|
||||
checkPositionIndexes(off, off + len, cbuf.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String str) {
|
||||
checkNotNull(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String str, int off, int len) {
|
||||
checkPositionIndexes(off, off + len, str.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer append(CharSequence csq) {
|
||||
checkNotNull(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer append(CharSequence csq, int start, int end) {
|
||||
checkPositionIndexes(start, end, csq.length());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer append(char c) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharStreams.nullWriter()";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Writer that sends all output to the given {@link Appendable}
|
||||
* target. Closing the writer will close the target if it is {@link Closeable},
|
||||
* and flushing the writer will flush the target if it is
|
||||
* {@link java.io.Flushable}.
|
||||
*
|
||||
* @param target the object to which output will be sent
|
||||
* @return a new Writer object, unless target is a Writer, in which case the
|
||||
* target is returned
|
||||
*/
|
||||
public static Writer asWriter(Appendable target) {
|
||||
if (target instanceof Writer) {
|
||||
return (Writer) target;
|
||||
}
|
||||
return new AppendableWriter(target);
|
||||
}
|
||||
|
||||
// TODO(user): Remove these once Input/OutputSupplier methods are removed
|
||||
|
||||
static Reader asReader(final Readable readable) {
|
||||
checkNotNull(readable);
|
||||
if (readable instanceof Reader) {
|
||||
return (Reader) readable;
|
||||
}
|
||||
return new Reader() {
|
||||
@Override
|
||||
public int read(char[] cbuf, int off, int len) throws IOException {
|
||||
return read(CharBuffer.wrap(cbuf, off, len));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(CharBuffer target) throws IOException {
|
||||
return readable.read(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (readable instanceof Closeable) {
|
||||
((Closeable) readable).close();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of the given {@code Readable} supplier as a
|
||||
* {@code CharSource}.
|
||||
*
|
||||
* <p>
|
||||
* This method is a temporary method provided for easing migration from
|
||||
* suppliers to sources and sinks.
|
||||
*
|
||||
* @since 15.0
|
||||
* @deprecated Convert all {@code InputSupplier<? extends Readable>}
|
||||
* implementations to extend {@link CharSource} or provide a method
|
||||
* for viewing the object as a {@code CharSource}. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static CharSource asCharSource(final InputSupplier<? extends Readable> supplier) {
|
||||
checkNotNull(supplier);
|
||||
return new CharSource() {
|
||||
@Override
|
||||
public Reader openStream() throws IOException {
|
||||
return asReader(supplier.getInput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharStreams.asCharSource(" + supplier + ")";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of the given {@code Appendable} supplier as a
|
||||
* {@code CharSink}.
|
||||
*
|
||||
* <p>
|
||||
* This method is a temporary method provided for easing migration from
|
||||
* suppliers to sources and sinks.
|
||||
*
|
||||
* @since 15.0
|
||||
* @deprecated Convert all {@code OutputSupplier<? extends Appendable>}
|
||||
* implementations to extend {@link CharSink} or provide a method
|
||||
* for viewing the object as a {@code CharSink}. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static CharSink asCharSink(final OutputSupplier<? extends Appendable> supplier) {
|
||||
checkNotNull(supplier);
|
||||
return new CharSink() {
|
||||
@Override
|
||||
public Writer openStream() throws IOException {
|
||||
return asWriter(supplier.getOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharStreams.asCharSink(" + supplier + ")";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // used internally where known to be safe
|
||||
static <R extends Reader> InputSupplier<R> asInputSupplier(CharSource source) {
|
||||
return (InputSupplier) checkNotNull(source);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // used internally where known to be safe
|
||||
static <W extends Writer> OutputSupplier<W> asOutputSupplier(CharSink sink) {
|
||||
return (OutputSupplier) checkNotNull(sink);
|
||||
}
|
||||
}
|
143
sources/main/java/com/google/common/io/Closeables.java
Normal file
143
sources/main/java/com/google/common/io/Closeables.java
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Utility methods for working with {@link Closeable} objects.
|
||||
*
|
||||
* @author Michael Lancaster
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class Closeables {
|
||||
@VisibleForTesting
|
||||
static final Logger logger = Logger.getLogger(Closeables.class.getName());
|
||||
|
||||
private Closeables() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a {@link Closeable}, with control over whether an {@code IOException}
|
||||
* may be thrown. This is primarily useful in a finally block, where a thrown
|
||||
* exception needs to be logged but not propagated (otherwise the original
|
||||
* exception will be lost).
|
||||
*
|
||||
* <p>
|
||||
* If {@code swallowIOException} is true then we never throw {@code IOException}
|
||||
* but merely log it.
|
||||
*
|
||||
* <p>
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* public void useStreamNicely() throws IOException {
|
||||
* SomeStream stream = new SomeStream("foo");
|
||||
* boolean threw = true;
|
||||
* try {
|
||||
* // ... code which does something with the stream ...
|
||||
* threw = false;
|
||||
* } finally {
|
||||
* // If an exception occurs, rethrow it only if threw==false:
|
||||
* Closeables.close(stream, threw);
|
||||
* }
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* @param closeable the {@code Closeable} object to be closed, or null,
|
||||
* in which case this method does nothing
|
||||
* @param swallowIOException if true, don't propagate IO exceptions thrown by
|
||||
* the {@code close} methods
|
||||
* @throws IOException if {@code swallowIOException} is false and {@code close}
|
||||
* throws an {@code IOException}.
|
||||
*/
|
||||
public static void close(@Nullable Closeable closeable, boolean swallowIOException) throws IOException {
|
||||
if (closeable == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException e) {
|
||||
if (swallowIOException) {
|
||||
logger.log(Level.WARNING, "IOException thrown while closing Closeable.", e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given {@link InputStream}, logging any {@code IOException} that's
|
||||
* thrown rather than propagating it.
|
||||
*
|
||||
* <p>
|
||||
* While it's not safe in the general case to ignore exceptions that are thrown
|
||||
* when closing an I/O resource, it should generally be safe in the case of a
|
||||
* resource that's being used only for reading, such as an {@code InputStream}.
|
||||
* Unlike with writable resources, there's no chance that a failure that occurs
|
||||
* when closing the stream indicates a meaningful problem such as a failure to
|
||||
* flush all bytes to the underlying resource.
|
||||
*
|
||||
* @param inputStream the input stream to be closed, or {@code null} in which
|
||||
* case this method does nothing
|
||||
* @since 17.0
|
||||
*/
|
||||
public static void closeQuietly(@Nullable InputStream inputStream) {
|
||||
try {
|
||||
close(inputStream, true);
|
||||
} catch (IOException impossible) {
|
||||
throw new AssertionError(impossible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given {@link Reader}, logging any {@code IOException} that's
|
||||
* thrown rather than propagating it.
|
||||
*
|
||||
* <p>
|
||||
* While it's not safe in the general case to ignore exceptions that are thrown
|
||||
* when closing an I/O resource, it should generally be safe in the case of a
|
||||
* resource that's being used only for reading, such as a {@code Reader}. Unlike
|
||||
* with writable resources, there's no chance that a failure that occurs when
|
||||
* closing the reader indicates a meaningful problem such as a failure to flush
|
||||
* all bytes to the underlying resource.
|
||||
*
|
||||
* @param reader the reader to be closed, or {@code null} in which case this
|
||||
* method does nothing
|
||||
* @since 17.0
|
||||
*/
|
||||
public static void closeQuietly(@Nullable Reader reader) {
|
||||
try {
|
||||
close(reader, true);
|
||||
} catch (IOException impossible) {
|
||||
throw new AssertionError(impossible);
|
||||
}
|
||||
}
|
||||
}
|
324
sources/main/java/com/google/common/io/Closer.java
Normal file
324
sources/main/java/com/google/common/io/Closer.java
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
/**
|
||||
* A {@link Closeable} that collects {@code Closeable} resources and closes them
|
||||
* all when it is {@linkplain #close closed}. This is intended to approximately
|
||||
* emulate the behavior of Java 7's <a href=
|
||||
* "http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html">
|
||||
* try-with-resources</a> statement in JDK6-compatible code. Running on Java 7,
|
||||
* code using this should be approximately equivalent in behavior to the same
|
||||
* code written with try-with-resources. Running on Java 6, exceptions that
|
||||
* cannot be thrown must be logged rather than being added to the thrown
|
||||
* exception as a suppressed exception.
|
||||
*
|
||||
* <p>
|
||||
* This class is intended to be used in the following pattern:
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* @code
|
||||
* Closer closer = Closer.create();
|
||||
* try {
|
||||
* InputStream in = closer.register(openInputStream());
|
||||
* OutputStream out = closer.register(openOutputStream());
|
||||
* // do stuff
|
||||
* } catch (Throwable e) {
|
||||
* // ensure that any checked exception types other than IOException that could
|
||||
* // be thrown are
|
||||
* // provided here, e.g. throw closer.rethrow(e, CheckedException.class);
|
||||
* throw closer.rethrow(e);
|
||||
* } finally {
|
||||
* closer.close();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that this try-catch-finally block is not equivalent to a
|
||||
* try-catch-finally block using try-with-resources. To get the equivalent of
|
||||
* that, you must wrap the above code in <i>another</i> try block in order to
|
||||
* catch any exception that may be thrown (including from the call to
|
||||
* {@code close()}).
|
||||
*
|
||||
* <p>
|
||||
* This pattern ensures the following:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Each {@code Closeable} resource that is successfully registered will be
|
||||
* closed later.</li>
|
||||
* <li>If a {@code Throwable} is thrown in the try block, no exceptions that
|
||||
* occur when attempting to close resources will be thrown from the finally
|
||||
* block. The throwable from the try block will be thrown.</li>
|
||||
* <li>If no exceptions or errors were thrown in the try block, the <i>first</i>
|
||||
* exception thrown by an attempt to close a resource will be thrown.</li>
|
||||
* <li>Any exception caught when attempting to close a resource that is
|
||||
* <i>not</i> thrown (because another exception is already being thrown) is
|
||||
* <i>suppressed</i>.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* An exception that is suppressed is not thrown. The method of suppression used
|
||||
* depends on the version of Java the code is running on:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>Java 7+:</b> Exceptions are suppressed by adding them to the exception
|
||||
* that <i>will</i> be thrown using
|
||||
* {@code Throwable.addSuppressed(Throwable)}.</li>
|
||||
* <li><b>Java 6:</b> Exceptions are suppressed by logging them instead.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Colin Decker
|
||||
* @since 14.0
|
||||
*/
|
||||
// Coffee's for {@link Closer closers} only.
|
||||
@Beta
|
||||
public final class Closer implements Closeable {
|
||||
|
||||
/**
|
||||
* The suppressor implementation to use for the current Java version.
|
||||
*/
|
||||
private static final Suppressor SUPPRESSOR = SuppressingSuppressor.isAvailable() ? SuppressingSuppressor.INSTANCE
|
||||
: LoggingSuppressor.INSTANCE;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Closer}.
|
||||
*/
|
||||
public static Closer create() {
|
||||
return new Closer(SUPPRESSOR);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
final Suppressor suppressor;
|
||||
|
||||
// only need space for 2 elements in most cases, so try to use the smallest
|
||||
// array possible
|
||||
private final Deque<Closeable> stack = new ArrayDeque<Closeable>(4);
|
||||
private Throwable thrown;
|
||||
|
||||
@VisibleForTesting
|
||||
Closer(Suppressor suppressor) {
|
||||
this.suppressor = checkNotNull(suppressor); // checkNotNull to satisfy null tests
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given {@code closeable} to be closed when this {@code Closer}
|
||||
* is {@linkplain #close closed}.
|
||||
*
|
||||
* @return the given {@code closeable}
|
||||
*/
|
||||
// close. this word no longer has any meaning to me.
|
||||
public <C extends Closeable> C register(@Nullable C closeable) {
|
||||
if (closeable != null) {
|
||||
stack.addFirst(closeable);
|
||||
}
|
||||
|
||||
return closeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given throwable and rethrows it. It will be rethrown as is if it
|
||||
* is an {@code IOException}, {@code RuntimeException} or {@code Error}.
|
||||
* Otherwise, it will be rethrown wrapped in a {@code RuntimeException}.
|
||||
* <b>Note:</b> Be sure to declare all of the checked exception types your try
|
||||
* block can throw when calling an overload of this method so as to avoid losing
|
||||
* the original exception type.
|
||||
*
|
||||
* <p>
|
||||
* This method always throws, and as such should be called as
|
||||
* {@code throw closer.rethrow(e);} to ensure the compiler knows that it will
|
||||
* throw.
|
||||
*
|
||||
* @return this method does not return; it always throws
|
||||
* @throws IOException when the given throwable is an IOException
|
||||
*/
|
||||
public RuntimeException rethrow(Throwable e) throws IOException {
|
||||
checkNotNull(e);
|
||||
thrown = e;
|
||||
Throwables.propagateIfPossible(e, IOException.class);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given throwable and rethrows it. It will be rethrown as is if it
|
||||
* is an {@code IOException}, {@code RuntimeException}, {@code Error} or a
|
||||
* checked exception of the given type. Otherwise, it will be rethrown wrapped
|
||||
* in a {@code RuntimeException}. <b>Note:</b> Be sure to declare all of the
|
||||
* checked exception types your try block can throw when calling an overload of
|
||||
* this method so as to avoid losing the original exception type.
|
||||
*
|
||||
* <p>
|
||||
* This method always throws, and as such should be called as
|
||||
* {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it
|
||||
* will throw.
|
||||
*
|
||||
* @return this method does not return; it always throws
|
||||
* @throws IOException when the given throwable is an IOException
|
||||
* @throws X when the given throwable is of the declared type X
|
||||
*/
|
||||
public <X extends Exception> RuntimeException rethrow(Throwable e, Class<X> declaredType) throws IOException, X {
|
||||
checkNotNull(e);
|
||||
thrown = e;
|
||||
Throwables.propagateIfPossible(e, IOException.class);
|
||||
Throwables.propagateIfPossible(e, declaredType);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given throwable and rethrows it. It will be rethrown as is if it
|
||||
* is an {@code IOException}, {@code RuntimeException}, {@code Error} or a
|
||||
* checked exception of either of the given types. Otherwise, it will be
|
||||
* rethrown wrapped in a {@code RuntimeException}. <b>Note:</b> Be sure to
|
||||
* declare all of the checked exception types your try block can throw when
|
||||
* calling an overload of this method so as to avoid losing the original
|
||||
* exception type.
|
||||
*
|
||||
* <p>
|
||||
* This method always throws, and as such should be called as
|
||||
* {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it
|
||||
* will throw.
|
||||
*
|
||||
* @return this method does not return; it always throws
|
||||
* @throws IOException when the given throwable is an IOException
|
||||
* @throws X1 when the given throwable is of the declared type X1
|
||||
* @throws X2 when the given throwable is of the declared type X2
|
||||
*/
|
||||
public <X1 extends Exception, X2 extends Exception> RuntimeException rethrow(Throwable e, Class<X1> declaredType1,
|
||||
Class<X2> declaredType2) throws IOException, X1, X2 {
|
||||
checkNotNull(e);
|
||||
thrown = e;
|
||||
Throwables.propagateIfPossible(e, IOException.class);
|
||||
Throwables.propagateIfPossible(e, declaredType1, declaredType2);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all {@code Closeable} instances that have been added to this
|
||||
* {@code Closer}. If an exception was thrown in the try block and passed to one
|
||||
* of the {@code exceptionThrown} methods, any exceptions thrown when attempting
|
||||
* to close a closeable will be suppressed. Otherwise, the <i>first</i>
|
||||
* exception to be thrown from an attempt to close a closeable will be thrown
|
||||
* and any additional exceptions that are thrown after that will be suppressed.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Throwable throwable = thrown;
|
||||
|
||||
// close closeables in LIFO order
|
||||
while (!stack.isEmpty()) {
|
||||
Closeable closeable = stack.removeFirst();
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Throwable e) {
|
||||
if (throwable == null) {
|
||||
throwable = e;
|
||||
} else {
|
||||
suppressor.suppress(closeable, throwable, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thrown == null && throwable != null) {
|
||||
Throwables.propagateIfPossible(throwable, IOException.class);
|
||||
throw new AssertionError(throwable); // not possible
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression strategy interface.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
interface Suppressor {
|
||||
/**
|
||||
* Suppresses the given exception ({@code suppressed}) which was thrown when
|
||||
* attempting to close the given closeable. {@code thrown} is the exception that
|
||||
* is actually being thrown from the method. Implementations of this method
|
||||
* should not throw under any circumstances.
|
||||
*/
|
||||
void suppress(Closeable closeable, Throwable thrown, Throwable suppressed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppresses exceptions by logging them.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static final class LoggingSuppressor implements Suppressor {
|
||||
|
||||
static final LoggingSuppressor INSTANCE = new LoggingSuppressor();
|
||||
|
||||
@Override
|
||||
public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) {
|
||||
// log to the same place as Closeables
|
||||
Closeables.logger.log(Level.WARNING, "Suppressing exception thrown when closing " + closeable, suppressed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppresses exceptions by adding them to the exception that will be thrown
|
||||
* using JDK7's addSuppressed(Throwable) mechanism.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static final class SuppressingSuppressor implements Suppressor {
|
||||
|
||||
static final SuppressingSuppressor INSTANCE = new SuppressingSuppressor();
|
||||
|
||||
static boolean isAvailable() {
|
||||
return addSuppressed != null;
|
||||
}
|
||||
|
||||
static final Method addSuppressed = getAddSuppressed();
|
||||
|
||||
private static Method getAddSuppressed() {
|
||||
try {
|
||||
return Throwable.class.getMethod("addSuppressed", Throwable.class);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) {
|
||||
// ensure no exceptions from addSuppressed
|
||||
if (thrown == suppressed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
addSuppressed.invoke(thrown, suppressed);
|
||||
} catch (Throwable e) {
|
||||
// if, somehow, IllegalAccessException or another exception is thrown, fall back
|
||||
// to logging
|
||||
LoggingSuppressor.INSTANCE.suppress(closeable, thrown, suppressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* An {@link InputStream} that counts the number of bytes read.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class CountingInputStream extends FilterInputStream {
|
||||
|
||||
private long count;
|
||||
private long mark = -1;
|
||||
|
||||
/**
|
||||
* Wraps another input stream, counting the number of bytes read.
|
||||
*
|
||||
* @param in the input stream to be wrapped
|
||||
*/
|
||||
public CountingInputStream(@Nullable InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
/** Returns the number of bytes read. */
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int result = in.read();
|
||||
if (result != -1) {
|
||||
count++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int result = in.read(b, off, len);
|
||||
if (result != -1) {
|
||||
count += result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long result = in.skip(n);
|
||||
count += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
in.mark(readlimit);
|
||||
mark = count;
|
||||
// it's okay to mark even if mark isn't supported, as reset won't work
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
if (!in.markSupported()) {
|
||||
throw new IOException("Mark not supported");
|
||||
}
|
||||
if (mark == -1) {
|
||||
throw new IOException("Mark not set");
|
||||
}
|
||||
|
||||
in.reset();
|
||||
count = mark;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* An OutputStream that counts the number of bytes written.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class CountingOutputStream extends FilterOutputStream {
|
||||
|
||||
private long count;
|
||||
|
||||
/**
|
||||
* Wraps another output stream, counting the number of bytes written.
|
||||
*
|
||||
* @param out the output stream to be wrapped
|
||||
*/
|
||||
public CountingOutputStream(@Nullable OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
/** Returns the number of bytes written. */
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
out.write(b, off, len);
|
||||
count += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
out.write(b);
|
||||
count++;
|
||||
}
|
||||
|
||||
// Overriding close() because FilterOutputStream's close() method pre-JDK8 has
|
||||
// bad behavior:
|
||||
// it silently ignores any exception thrown by flush(). Instead, just close the
|
||||
// delegate stream.
|
||||
// It should flush itself if necessary.
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
}
|
||||
}
|
31
sources/main/java/com/google/common/io/FileWriteMode.java
Normal file
31
sources/main/java/com/google/common/io/FileWriteMode.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
/**
|
||||
* Modes for opening a file for writing. The default when mode when none is
|
||||
* specified is to truncate the file before writing.
|
||||
*
|
||||
* @author Colin Decker
|
||||
*/
|
||||
public enum FileWriteMode {
|
||||
/**
|
||||
* Specifies that writes to the opened file should append to the end of the
|
||||
* file.
|
||||
*/
|
||||
APPEND
|
||||
}
|
79
sources/main/java/com/google/common/io/Flushables.java
Normal file
79
sources/main/java/com/google/common/io/Flushables.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.Flushable;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* Utility methods for working with {@link Flushable} objects.
|
||||
*
|
||||
* @author Michael Lancaster
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class Flushables {
|
||||
private static final Logger logger = Logger.getLogger(Flushables.class.getName());
|
||||
|
||||
private Flushables() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush a {@link Flushable}, with control over whether an {@code IOException}
|
||||
* may be thrown.
|
||||
*
|
||||
* <p>
|
||||
* If {@code swallowIOException} is true, then we don't rethrow
|
||||
* {@code IOException}, but merely log it.
|
||||
*
|
||||
* @param flushable the {@code Flushable} object to be flushed.
|
||||
* @param swallowIOException if true, don't propagate IO exceptions thrown by
|
||||
* the {@code flush} method
|
||||
* @throws IOException if {@code swallowIOException} is false and
|
||||
* {@link Flushable#flush} throws an {@code IOException}.
|
||||
* @see Closeables#close
|
||||
*/
|
||||
public static void flush(Flushable flushable, boolean swallowIOException) throws IOException {
|
||||
try {
|
||||
flushable.flush();
|
||||
} catch (IOException e) {
|
||||
if (swallowIOException) {
|
||||
logger.log(Level.WARNING, "IOException thrown while flushing Flushable.", e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@code flush(flushable, true)}, but with no
|
||||
* {@code IOException} in the signature.
|
||||
*
|
||||
* @param flushable the {@code Flushable} object to be flushed.
|
||||
*/
|
||||
public static void flushQuietly(Flushable flushable) {
|
||||
try {
|
||||
flush(flushable, true);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "IOException should not have been thrown.", e);
|
||||
}
|
||||
}
|
||||
}
|
241
sources/main/java/com/google/common/io/GwtWorkarounds.java
Normal file
241
sources/main/java/com/google/common/io/GwtWorkarounds.java
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkPositionIndexes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* Provides simple GWT-compatible substitutes for {@code InputStream},
|
||||
* {@code OutputStream}, {@code Reader}, and {@code Writer} so that
|
||||
* {@code BaseEncoding} can use streaming implementations while remaining
|
||||
* GWT-compatible.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
final class GwtWorkarounds {
|
||||
private GwtWorkarounds() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A GWT-compatible substitute for a {@code Reader}.
|
||||
*/
|
||||
interface CharInput {
|
||||
int read() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views a {@code Reader} as a {@code CharInput}.
|
||||
*/
|
||||
@GwtIncompatible("Reader")
|
||||
static CharInput asCharInput(final Reader reader) {
|
||||
checkNotNull(reader);
|
||||
return new CharInput() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return reader.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
reader.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Views a {@code CharSequence} as a {@code CharInput}.
|
||||
*/
|
||||
static CharInput asCharInput(final CharSequence chars) {
|
||||
checkNotNull(chars);
|
||||
return new CharInput() {
|
||||
int index = 0;
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if (index < chars.length()) {
|
||||
return chars.charAt(index++);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
index = chars.length();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A GWT-compatible substitute for an {@code InputStream}.
|
||||
*/
|
||||
interface ByteInput {
|
||||
int read() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views a {@code ByteInput} as an {@code InputStream}.
|
||||
*/
|
||||
@GwtIncompatible("InputStream")
|
||||
static InputStream asInputStream(final ByteInput input) {
|
||||
checkNotNull(input);
|
||||
return new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return input.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
checkNotNull(b);
|
||||
checkPositionIndexes(off, off + len, b.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
int firstByte = read();
|
||||
if (firstByte == -1) {
|
||||
return -1;
|
||||
}
|
||||
b[off] = (byte) firstByte;
|
||||
for (int dst = 1; dst < len; dst++) {
|
||||
int readByte = read();
|
||||
if (readByte == -1) {
|
||||
return dst;
|
||||
}
|
||||
b[off + dst] = (byte) readByte;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
input.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A GWT-compatible substitute for an {@code OutputStream}.
|
||||
*/
|
||||
interface ByteOutput {
|
||||
void write(byte b) throws IOException;
|
||||
|
||||
void flush() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views a {@code ByteOutput} as an {@code OutputStream}.
|
||||
*/
|
||||
@GwtIncompatible("OutputStream")
|
||||
static OutputStream asOutputStream(final ByteOutput output) {
|
||||
checkNotNull(output);
|
||||
return new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
output.write((byte) b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
output.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
output.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A GWT-compatible substitute for a {@code Writer}.
|
||||
*/
|
||||
interface CharOutput {
|
||||
void write(char c) throws IOException;
|
||||
|
||||
void flush() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views a {@code Writer} as a {@code CharOutput}.
|
||||
*/
|
||||
@GwtIncompatible("Writer")
|
||||
static CharOutput asCharOutput(final Writer writer) {
|
||||
checkNotNull(writer);
|
||||
return new CharOutput() {
|
||||
@Override
|
||||
public void write(char c) throws IOException {
|
||||
writer.append(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
writer.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code CharOutput} whose {@code toString()} method can be used to
|
||||
* get the combined output.
|
||||
*/
|
||||
static CharOutput stringBuilderOutput(int initialSize) {
|
||||
final StringBuilder builder = new StringBuilder(initialSize);
|
||||
return new CharOutput() {
|
||||
|
||||
@Override
|
||||
public void write(char c) {
|
||||
builder.append(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return builder.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
48
sources/main/java/com/google/common/io/InputSupplier.java
Normal file
48
sources/main/java/com/google/common/io/InputSupplier.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A factory for readable streams of bytes or characters.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
* @deprecated For {@code InputSupplier<? extends InputStream>}, use
|
||||
* {@link ByteSource} instead. For
|
||||
* {@code InputSupplier<? extends Reader>}, use {@link CharSource}.
|
||||
* Implementations of {@code InputSupplier} that don't fall into one
|
||||
* of those categories do not benefit from any of the methods in
|
||||
* {@code common.io} and should use a different interface. This
|
||||
* interface is scheduled for removal in June 2015.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface InputSupplier<T> {
|
||||
|
||||
/**
|
||||
* Returns an object that encapsulates a readable resource.
|
||||
* <p>
|
||||
* Like {@link Iterable#iterator}, this method may be called repeatedly to get
|
||||
* independent channels to the same underlying resource.
|
||||
* <p>
|
||||
* Where the channel maintains a position within the resource, moving that
|
||||
* cursor within one channel should not affect the starting position of channels
|
||||
* returned by other calls.
|
||||
*/
|
||||
T getInput() throws IOException;
|
||||
}
|
117
sources/main/java/com/google/common/io/LineBuffer.java
Normal file
117
sources/main/java/com/google/common/io/LineBuffer.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Package-protected abstract class that implements the line reading algorithm
|
||||
* used by {@link LineReader}. Line separators are per
|
||||
* {@link java.io.BufferedReader}: line feed, carriage return, or carriage
|
||||
* return followed immediately by a linefeed.
|
||||
*
|
||||
* <p>
|
||||
* Subclasses must implement {@link #handleLine}, call {@link #add} to pass
|
||||
* character data, and call {@link #finish} at the end of stream.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
*/
|
||||
abstract class LineBuffer {
|
||||
/** Holds partial line contents. */
|
||||
private StringBuilder line = new StringBuilder();
|
||||
/** Whether a line ending with a CR is pending processing. */
|
||||
private boolean sawReturn;
|
||||
|
||||
/**
|
||||
* Process additional characters from the stream. When a line separator is found
|
||||
* the contents of the line and the line separator itself are passed to the
|
||||
* abstract {@link #handleLine} method.
|
||||
*
|
||||
* @param cbuf the character buffer to process
|
||||
* @param off the offset into the buffer
|
||||
* @param len the number of characters to process
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @see #finish
|
||||
*/
|
||||
protected void add(char[] cbuf, int off, int len) throws IOException {
|
||||
int pos = off;
|
||||
if (sawReturn && len > 0) {
|
||||
// Last call to add ended with a CR; we can handle the line now.
|
||||
if (finishLine(cbuf[pos] == '\n')) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int start = pos;
|
||||
for (int end = off + len; pos < end; pos++) {
|
||||
switch (cbuf[pos]) {
|
||||
case '\r':
|
||||
line.append(cbuf, start, pos - start);
|
||||
sawReturn = true;
|
||||
if (pos + 1 < end) {
|
||||
if (finishLine(cbuf[pos + 1] == '\n')) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
start = pos + 1;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
line.append(cbuf, start, pos - start);
|
||||
finishLine(true);
|
||||
start = pos + 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
line.append(cbuf, start, off + len - start);
|
||||
}
|
||||
|
||||
/** Called when a line is complete. */
|
||||
private boolean finishLine(boolean sawNewline) throws IOException {
|
||||
handleLine(line.toString(), sawReturn ? (sawNewline ? "\r\n" : "\r") : (sawNewline ? "\n" : ""));
|
||||
line = new StringBuilder();
|
||||
sawReturn = false;
|
||||
return sawNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must call this method after finishing character processing, in
|
||||
* order to ensure that any unterminated line in the buffer is passed to
|
||||
* {@link #handleLine}.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
protected void finish() throws IOException {
|
||||
if (sawReturn || line.length() > 0) {
|
||||
finishLine(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for each line found in the character data passed to {@link #add}.
|
||||
*
|
||||
* @param line a line of text (possibly empty), without any line separators
|
||||
* @param end the line separator; one of {@code "\r"}, {@code "\n"},
|
||||
* {@code "\r\n"}, or {@code ""}
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
protected abstract void handleLine(String line, String end) throws IOException;
|
||||
}
|
46
sources/main/java/com/google/common/io/LineProcessor.java
Normal file
46
sources/main/java/com/google/common/io/LineProcessor.java
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* A callback to be used with the streaming {@code readLines} methods.
|
||||
*
|
||||
* <p>
|
||||
* {@link #processLine} will be called for each line that is read, and should
|
||||
* return {@code false} when you want to stop processing.
|
||||
*
|
||||
* @author Miles Barr
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public interface LineProcessor<T> {
|
||||
|
||||
/**
|
||||
* This method will be called once for each line.
|
||||
*
|
||||
* @param line the line read from the input, without delimiter
|
||||
* @return true to continue processing, false to stop
|
||||
*/
|
||||
boolean processLine(String line) throws IOException;
|
||||
|
||||
/** Return the result of processing all the lines. */
|
||||
T getResult();
|
||||
}
|
85
sources/main/java/com/google/common/io/LineReader.java
Normal file
85
sources/main/java/com/google/common/io/LineReader.java
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* A class for reading lines of text. Provides the same functionality as
|
||||
* {@link java.io.BufferedReader#readLine()} but for all {@link Readable}
|
||||
* objects, not just instances of {@link Reader}.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class LineReader {
|
||||
private final Readable readable;
|
||||
private final Reader reader;
|
||||
private final char[] buf = new char[0x1000]; // 4K
|
||||
private final CharBuffer cbuf = CharBuffer.wrap(buf);
|
||||
|
||||
private final Queue<String> lines = new LinkedList<String>();
|
||||
private final LineBuffer lineBuf = new LineBuffer() {
|
||||
@Override
|
||||
protected void handleLine(String line, String end) {
|
||||
lines.add(line);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance that will read lines from the given {@code Readable}
|
||||
* object.
|
||||
*/
|
||||
public LineReader(Readable readable) {
|
||||
this.readable = checkNotNull(readable);
|
||||
this.reader = (readable instanceof Reader) ? (Reader) readable : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line of text. A line is considered to be terminated by any one of a
|
||||
* line feed ({@code '\n'}), a carriage return ({@code '\r'}), or a carriage
|
||||
* return followed immediately by a linefeed ({@code "\r\n"}).
|
||||
*
|
||||
* @return a {@code String} containing the contents of the line, not including
|
||||
* any line-termination characters, or {@code null} if the end of the
|
||||
* stream has been reached.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public String readLine() throws IOException {
|
||||
while (lines.peek() == null) {
|
||||
cbuf.clear();
|
||||
// The default implementation of Reader#read(CharBuffer) allocates a
|
||||
// temporary char[], so we call Reader#read(char[], int, int) instead.
|
||||
int read = (reader != null) ? reader.read(buf, 0, buf.length) : readable.read(cbuf);
|
||||
if (read == -1) {
|
||||
lineBuf.finish();
|
||||
break;
|
||||
}
|
||||
lineBuf.add(buf, 0, read);
|
||||
}
|
||||
return lines.poll();
|
||||
}
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
/**
|
||||
* An implementation of {@link DataInput} that uses little-endian byte ordering
|
||||
* for reading {@code short}, {@code int}, {@code float}, {@code double}, and
|
||||
* {@code long} values.
|
||||
* <p>
|
||||
* <b>Note:</b> This class intentionally violates the specification of its
|
||||
* supertype {@code DataInput}, which explicitly requires big-endian byte order.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Keith Bottner
|
||||
* @since 8.0
|
||||
*/
|
||||
@Beta
|
||||
public final class LittleEndianDataInputStream extends FilterInputStream implements DataInput {
|
||||
|
||||
/**
|
||||
* Creates a {@code LittleEndianDataInputStream} that wraps the given stream.
|
||||
*
|
||||
* @param in the stream to delegate to
|
||||
*/
|
||||
public LittleEndianDataInputStream(InputStream in) {
|
||||
super(Preconditions.checkNotNull(in));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will throw an {@link UnsupportedOperationException}.
|
||||
*/
|
||||
@Override
|
||||
public String readLine() {
|
||||
throw new UnsupportedOperationException("readLine is not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFully(byte[] b) throws IOException {
|
||||
ByteStreams.readFully(this, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFully(byte[] b, int off, int len) throws IOException {
|
||||
ByteStreams.readFully(this, b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int skipBytes(int n) throws IOException {
|
||||
return (int) in.skip(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedByte() throws IOException {
|
||||
int b1 = in.read();
|
||||
if (0 > b1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
return b1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned {@code short} as specified by
|
||||
* {@link DataInputStream#readUnsignedShort()}, except using little-endian byte
|
||||
* order.
|
||||
*
|
||||
* @return the next two bytes of the input stream, interpreted as an unsigned
|
||||
* 16-bit integer in little-endian byte order
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int readUnsignedShort() throws IOException {
|
||||
byte b1 = readAndCheckByte();
|
||||
byte b2 = readAndCheckByte();
|
||||
|
||||
return Ints.fromBytes((byte) 0, (byte) 0, b2, b1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer as specified by {@link DataInputStream#readInt()}, except
|
||||
* using little-endian byte order.
|
||||
*
|
||||
* @return the next four bytes of the input stream, interpreted as an
|
||||
* {@code int} in little-endian byte order
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int readInt() throws IOException {
|
||||
byte b1 = readAndCheckByte();
|
||||
byte b2 = readAndCheckByte();
|
||||
byte b3 = readAndCheckByte();
|
||||
byte b4 = readAndCheckByte();
|
||||
|
||||
return Ints.fromBytes(b4, b3, b2, b1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@code long} as specified by {@link DataInputStream#readLong()},
|
||||
* except using little-endian byte order.
|
||||
*
|
||||
* @return the next eight bytes of the input stream, interpreted as a
|
||||
* {@code long} in little-endian byte order
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public long readLong() throws IOException {
|
||||
byte b1 = readAndCheckByte();
|
||||
byte b2 = readAndCheckByte();
|
||||
byte b3 = readAndCheckByte();
|
||||
byte b4 = readAndCheckByte();
|
||||
byte b5 = readAndCheckByte();
|
||||
byte b6 = readAndCheckByte();
|
||||
byte b7 = readAndCheckByte();
|
||||
byte b8 = readAndCheckByte();
|
||||
|
||||
return Longs.fromBytes(b8, b7, b6, b5, b4, b3, b2, b1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@code float} as specified by {@link DataInputStream#readFloat()},
|
||||
* except using little-endian byte order.
|
||||
*
|
||||
* @return the next four bytes of the input stream, interpreted as a
|
||||
* {@code float} in little-endian byte order
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat(readInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@code double} as specified by {@link DataInputStream#readDouble()},
|
||||
* except using little-endian byte order.
|
||||
*
|
||||
* @return the next eight bytes of the input stream, interpreted as a
|
||||
* {@code double} in little-endian byte order
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public double readDouble() throws IOException {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readUTF() throws IOException {
|
||||
return new DataInputStream(in).readUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@code short} as specified by {@link DataInputStream#readShort()},
|
||||
* except using little-endian byte order.
|
||||
*
|
||||
* @return the next two bytes of the input stream, interpreted as a
|
||||
* {@code short} in little-endian byte order.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
@Override
|
||||
public short readShort() throws IOException {
|
||||
return (short) readUnsignedShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a char as specified by {@link DataInputStream#readChar()}, except using
|
||||
* little-endian byte order.
|
||||
*
|
||||
* @return the next two bytes of the input stream, interpreted as a {@code char}
|
||||
* in little-endian byte order
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public char readChar() throws IOException {
|
||||
return (char) readUnsignedShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte() throws IOException {
|
||||
return (byte) readUnsignedByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() throws IOException {
|
||||
return readUnsignedByte() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte from the input stream checking that the end of file (EOF) has
|
||||
* not been encountered.
|
||||
*
|
||||
* @return byte read from input
|
||||
* @throws IOException if an error is encountered while reading
|
||||
* @throws EOFException if the end of file (EOF) is encountered.
|
||||
*/
|
||||
private byte readAndCheckByte() throws IOException, EOFException {
|
||||
int b1 = in.read();
|
||||
|
||||
if (-1 == b1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
return (byte) b1;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
/**
|
||||
* An implementation of {@link DataOutput} that uses little-endian byte ordering
|
||||
* for writing {@code char}, {@code short}, {@code int}, {@code float}, {@code
|
||||
* double}, and {@code long} values.
|
||||
* <p>
|
||||
* <b>Note:</b> This class intentionally violates the specification of its
|
||||
* supertype {@code DataOutput}, which explicitly requires big-endian byte
|
||||
* order.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Keith Bottner
|
||||
* @since 8.0
|
||||
*/
|
||||
@Beta
|
||||
public class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput {
|
||||
|
||||
/**
|
||||
* Creates a {@code LittleEndianDataOutputStream} that wraps the given stream.
|
||||
*
|
||||
* @param out the stream to delegate to
|
||||
*/
|
||||
public LittleEndianDataOutputStream(OutputStream out) {
|
||||
super(new DataOutputStream(Preconditions.checkNotNull(out)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
// Override slow FilterOutputStream impl
|
||||
out.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBoolean(boolean v) throws IOException {
|
||||
((DataOutputStream) out).writeBoolean(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeByte(int v) throws IOException {
|
||||
((DataOutputStream) out).writeByte(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated The semantics of {@code writeBytes(String s)} are considered
|
||||
* dangerous. Please use {@link #writeUTF(String s)},
|
||||
* {@link #writeChars(String s)} or another write method instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void writeBytes(String s) throws IOException {
|
||||
((DataOutputStream) out).writeBytes(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a char as specified by {@link DataOutputStream#writeChar(int)}, except
|
||||
* using little-endian byte order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeChar(int v) throws IOException {
|
||||
writeShort(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code String} as specified by
|
||||
* {@link DataOutputStream#writeChars(String)}, except each character is written
|
||||
* using little-endian byte order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeChars(String s) throws IOException {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
writeChar(s.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code double} as specified by
|
||||
* {@link DataOutputStream#writeDouble(double)}, except using little-endian byte
|
||||
* order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeDouble(double v) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code float} as specified by
|
||||
* {@link DataOutputStream#writeFloat(float)}, except using little-endian byte
|
||||
* order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeFloat(float v) throws IOException {
|
||||
writeInt(Float.floatToIntBits(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an {@code int} as specified by {@link DataOutputStream#writeInt(int)},
|
||||
* except using little-endian byte order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeInt(int v) throws IOException {
|
||||
out.write(0xFF & v);
|
||||
out.write(0xFF & (v >> 8));
|
||||
out.write(0xFF & (v >> 16));
|
||||
out.write(0xFF & (v >> 24));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code long} as specified by
|
||||
* {@link DataOutputStream#writeLong(long)}, except using little-endian byte
|
||||
* order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeLong(long v) throws IOException {
|
||||
byte[] bytes = Longs.toByteArray(Long.reverseBytes(v));
|
||||
write(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code short} as specified by
|
||||
* {@link DataOutputStream#writeShort(int)}, except using little-endian byte
|
||||
* order.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void writeShort(int v) throws IOException {
|
||||
out.write(0xFF & v);
|
||||
out.write(0xFF & (v >> 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUTF(String str) throws IOException {
|
||||
((DataOutputStream) out).writeUTF(str);
|
||||
}
|
||||
|
||||
// Overriding close() because FilterOutputStream's close() method pre-JDK8 has
|
||||
// bad behavior:
|
||||
// it silently ignores any exception thrown by flush(). Instead, just close the
|
||||
// delegate stream.
|
||||
// It should flush itself if necessary.
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
}
|
||||
}
|
123
sources/main/java/com/google/common/io/MultiInputStream.java
Normal file
123
sources/main/java/com/google/common/io/MultiInputStream.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An {@link InputStream} that concatenates multiple substreams. At most one
|
||||
* stream will be open at a time.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
*/
|
||||
final class MultiInputStream extends InputStream {
|
||||
|
||||
private Iterator<? extends ByteSource> it;
|
||||
private InputStream in;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param it an iterator of I/O suppliers that will provide each substream
|
||||
*/
|
||||
public MultiInputStream(Iterator<? extends ByteSource> it) throws IOException {
|
||||
this.it = checkNotNull(it);
|
||||
advance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} finally {
|
||||
in = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current input stream and opens the next one, if any.
|
||||
*/
|
||||
private void advance() throws IOException {
|
||||
close();
|
||||
if (it.hasNext()) {
|
||||
in = it.next().openStream();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
if (in == null) {
|
||||
return 0;
|
||||
}
|
||||
return in.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (in == null) {
|
||||
return -1;
|
||||
}
|
||||
int result = in.read();
|
||||
if (result == -1) {
|
||||
advance();
|
||||
return read();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@Nullable byte[] b, int off, int len) throws IOException {
|
||||
if (in == null) {
|
||||
return -1;
|
||||
}
|
||||
int result = in.read(b, off, len);
|
||||
if (result == -1) {
|
||||
advance();
|
||||
return read(b, off, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
if (in == null || n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
long result = in.skip(n);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
if (read() == -1) {
|
||||
return 0;
|
||||
}
|
||||
return 1 + in.skip(n - 1);
|
||||
}
|
||||
}
|
95
sources/main/java/com/google/common/io/MultiReader.java
Normal file
95
sources/main/java/com/google/common/io/MultiReader.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* A {@link Reader} that concatenates multiple readers.
|
||||
*
|
||||
* @author Bin Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
class MultiReader extends Reader {
|
||||
private final Iterator<? extends CharSource> it;
|
||||
private Reader current;
|
||||
|
||||
MultiReader(Iterator<? extends CharSource> readers) throws IOException {
|
||||
this.it = readers;
|
||||
advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current reader and opens the next one, if any.
|
||||
*/
|
||||
private void advance() throws IOException {
|
||||
close();
|
||||
if (it.hasNext()) {
|
||||
current = it.next().openStream();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@Nullable char cbuf[], int off, int len) throws IOException {
|
||||
if (current == null) {
|
||||
return -1;
|
||||
}
|
||||
int result = current.read(cbuf, off, len);
|
||||
if (result == -1) {
|
||||
advance();
|
||||
return read(cbuf, off, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
Preconditions.checkArgument(n >= 0, "n is negative");
|
||||
if (n > 0) {
|
||||
while (current != null) {
|
||||
long result = current.skip(n);
|
||||
if (result > 0) {
|
||||
return result;
|
||||
}
|
||||
advance();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ready() throws IOException {
|
||||
return (current != null) && current.ready();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (current != null) {
|
||||
try {
|
||||
current.close();
|
||||
} finally {
|
||||
current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
sources/main/java/com/google/common/io/OutputSupplier.java
Normal file
48
sources/main/java/com/google/common/io/OutputSupplier.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A factory for writable streams of bytes or characters.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @since 1.0
|
||||
* @deprecated For {@code OutputSupplier<? extends OutputStream>}, use
|
||||
* {@link ByteSink} instead. For
|
||||
* {@code OutputSupplier<? extends Writer>}, use {@link CharSink}.
|
||||
* Implementations of {@code OutputSupplier} that don't fall into
|
||||
* one of those categories do not benefit from any of the methods in
|
||||
* {@code common.io} and should use a different interface. This
|
||||
* interface is scheduled for removal in June 2015.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface OutputSupplier<T> {
|
||||
|
||||
/**
|
||||
* Returns an object that encapsulates a writable resource.
|
||||
* <p>
|
||||
* Like {@link Iterable#iterator}, this method may be called repeatedly to get
|
||||
* independent channels to the same underlying resource.
|
||||
* <p>
|
||||
* Where the channel maintains a position within the resource, moving that
|
||||
* cursor within one channel should not affect the starting position of channels
|
||||
* returned by other calls.
|
||||
*/
|
||||
T getOutput() throws IOException;
|
||||
}
|
241
sources/main/java/com/google/common/io/Resources.java
Normal file
241
sources/main/java/com/google/common/io/Resources.java
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Provides utility methods for working with resources in the classpath. Note
|
||||
* that even though these methods use {@link URL} parameters, they are usually
|
||||
* not appropriate for HTTP or other non-classpath resources.
|
||||
*
|
||||
* <p>
|
||||
* All method parameters must be non-null unless documented otherwise.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Ben Yu
|
||||
* @author Colin Decker
|
||||
* @since 1.0
|
||||
*/
|
||||
@Beta
|
||||
public final class Resources {
|
||||
private Resources() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory that will supply instances of {@link InputStream} that read
|
||||
* from the given URL.
|
||||
*
|
||||
* @param url the URL to read from
|
||||
* @return the factory
|
||||
* @deprecated Use {@link #asByteSource(URL)} instead. This method is scheduled
|
||||
* for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static InputSupplier<InputStream> newInputStreamSupplier(URL url) {
|
||||
return ByteStreams.asInputSupplier(asByteSource(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ByteSource} that reads from the given URL.
|
||||
*
|
||||
* @since 14.0
|
||||
*/
|
||||
public static ByteSource asByteSource(URL url) {
|
||||
return new UrlByteSource(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* A byte source that reads from a URL using {@link URL#openStream()}.
|
||||
*/
|
||||
private static final class UrlByteSource extends ByteSource {
|
||||
|
||||
private final URL url;
|
||||
|
||||
private UrlByteSource(URL url) {
|
||||
this.url = checkNotNull(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openStream() throws IOException {
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Resources.asByteSource(" + url + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory that will supply instances of {@link InputStreamReader}
|
||||
* that read a URL using the given character set.
|
||||
*
|
||||
* @param url the URL to read from
|
||||
* @param charset the charset used to decode the input stream; see
|
||||
* {@link Charsets} for helpful predefined constants
|
||||
* @return the factory
|
||||
* @deprecated Use {@link #asCharSource(URL, Charset)} instead. This method is
|
||||
* scheduled for removal in Guava 18.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static InputSupplier<InputStreamReader> newReaderSupplier(URL url, Charset charset) {
|
||||
return CharStreams.asInputSupplier(asCharSource(url, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link CharSource} that reads from the given URL using the given
|
||||
* character set.
|
||||
*
|
||||
* @since 14.0
|
||||
*/
|
||||
public static CharSource asCharSource(URL url, Charset charset) {
|
||||
return asByteSource(url).asCharSource(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all bytes from a URL into a byte array.
|
||||
*
|
||||
* @param url the URL to read from
|
||||
* @return a byte array containing all the bytes from the URL
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static byte[] toByteArray(URL url) throws IOException {
|
||||
return asByteSource(url).read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all characters from a URL into a {@link String}, using the given
|
||||
* character set.
|
||||
*
|
||||
* @param url the URL to read from
|
||||
* @param charset the charset used to decode the input stream; see
|
||||
* {@link Charsets} for helpful predefined constants
|
||||
* @return a string containing all the characters from the URL
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public static String toString(URL url, Charset charset) throws IOException {
|
||||
return asCharSource(url, charset).read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams lines from a URL, stopping when our callback returns false, or we
|
||||
* have read all of the lines.
|
||||
*
|
||||
* @param url the URL to read from
|
||||
* @param charset the charset used to decode the input stream; see
|
||||
* {@link Charsets} for helpful predefined constants
|
||||
* @param callback the LineProcessor to use to handle the lines
|
||||
* @return the output of processing the lines
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static <T> T readLines(URL url, Charset charset, LineProcessor<T> callback) throws IOException {
|
||||
return CharStreams.readLines(newReaderSupplier(url, charset), callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all of the lines from a URL. The lines do not include line-termination
|
||||
* characters, but do include other leading and trailing whitespace.
|
||||
*
|
||||
* <p>
|
||||
* This method returns a mutable {@code List}. For an {@code ImmutableList}, use
|
||||
* {@code Resources.asCharSource(url, charset).readLines()}.
|
||||
*
|
||||
* @param url the URL to read from
|
||||
* @param charset the charset used to decode the input stream; see
|
||||
* {@link Charsets} for helpful predefined constants
|
||||
* @return a mutable {@link List} containing all the lines
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static List<String> readLines(URL url, Charset charset) throws IOException {
|
||||
// don't use asCharSource(url, charset).readLines() because that returns
|
||||
// an immutable list, which would change the behavior of this method
|
||||
return readLines(url, charset, new LineProcessor<List<String>>() {
|
||||
final List<String> result = Lists.newArrayList();
|
||||
|
||||
@Override
|
||||
public boolean processLine(String line) {
|
||||
result.add(line);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getResult() {
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all bytes from a URL to an output stream.
|
||||
*
|
||||
* @param from the URL to read from
|
||||
* @param to the output stream
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void copy(URL from, OutputStream to) throws IOException {
|
||||
asByteSource(from).copyTo(to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code URL} pointing to {@code resourceName} if the resource is
|
||||
* found using the {@linkplain Thread#getContextClassLoader() context class
|
||||
* loader}. In simple environments, the context class loader will find resources
|
||||
* from the class path. In environments where different threads can have
|
||||
* different class loaders, for example app servers, the context class loader
|
||||
* will typically have been set to an appropriate loader for the current thread.
|
||||
*
|
||||
* <p>
|
||||
* In the unusual case where the context class loader is null, the class loader
|
||||
* that loaded this class ({@code Resources}) will be used instead.
|
||||
*
|
||||
* @throws IllegalArgumentException if the resource is not found
|
||||
*/
|
||||
public static URL getResource(String resourceName) {
|
||||
ClassLoader loader = Objects.firstNonNull(Thread.currentThread().getContextClassLoader(),
|
||||
Resources.class.getClassLoader());
|
||||
URL url = loader.getResource(resourceName);
|
||||
checkArgument(url != null, "resource %s not found.", resourceName);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a {@code resourceName} that is relative to {@code contextClass},
|
||||
* returns a {@code URL} pointing to the named resource.
|
||||
*
|
||||
* @throws IllegalArgumentException if the resource is not found
|
||||
*/
|
||||
public static URL getResource(Class<?> contextClass, String resourceName) {
|
||||
URL url = contextClass.getResource(resourceName);
|
||||
checkArgument(url != null, "resource %s relative to %s not found.", resourceName, contextClass.getName());
|
||||
return url;
|
||||
}
|
||||
}
|
42
sources/main/java/com/google/common/io/package-info.java
Normal file
42
sources/main/java/com/google/common/io/package-info.java
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains utility methods and classes for working with Java I/O;
|
||||
* for example input streams, output streams, readers, writers, and files.
|
||||
*
|
||||
* <p>
|
||||
* At the core of this package are the Source/Sink types:
|
||||
* {@link com.google.common.io.ByteSource ByteSource},
|
||||
* {@link com.google.common.io.CharSource CharSource},
|
||||
* {@link com.google.common.io.ByteSink ByteSink} and
|
||||
* {@link com.google.common.io.CharSink CharSink}. They are factories for I/O
|
||||
* streams that provide many convenience methods that handle both opening and
|
||||
* closing streams for you.
|
||||
*
|
||||
* <p>
|
||||
* This package is a part of the open-source
|
||||
* <a href="http://guava-libraries.googlecode.com">Guava libraries</a>. For more
|
||||
* information on Sources and Sinks as well as other features of this package,
|
||||
* see <a href="https://code.google.com/p/guava-libraries/wiki/IOExplained">I/O
|
||||
* Explained</a> on the Guava wiki.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.google.common.io;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
Reference in New Issue
Block a user