2023-12-16
Timeout.cancel()
prevents a timeout from firing.watchosX86
Kotlin/Native target. From the Kotlin blog, ‘This is an obsolete simulator for Intel Macs. Use the watchosX64 target instead.’watchosDeviceArm64
Kotlin/Native target.Timeout
APIs that accept kotlin.time.Duration
.2023-10-01
metadata
functions on ZipFileSystem
. We had a bug where we were closing the .zip
file, but not a stream inside of it. We would have prevented this bug if only we’d used FakeFileSystem.checkNoOpenFiles()
in our tests!ResourceFileSystem.read()
. This operation doesn't need this index, and building it is potentially expensive.linuxArm64
). Note that we haven't yet added CI test coverage for this platform.2023-10-01
XLEN
) is 32 KiB or larger.2023-08-02
WasiFileSystem
. This is in the new okio-wasifilesystem
module. It requires the preview1 WASI API. We’ll make backwards-incompatible upgrades to new WASI API versions as they become available.FileSystem.list()
had always returned absolute paths, even when the target directory was supplied as a relative path.FileHandle
on Kotlin/Native.2023-07-07
java.nio.file.FileSystem
) as an Okio FileSystem using fileSystem.asOkioFileSystem()
.AssetManager
as an Okio FileSystem using AssetFileSystem
. This is in the new okio-assetfilesystem
module. Android applications should prefer this over FileSystem.RESOURCES
as it’s faster to load.XLEN
) is 32 KiB or larger.FakeFileSystem.canonicalize()
.createdAtMillis
in NodeJsFileSystem
file metadata. We were incorrectly using ctimeMs
, where c
means changed, not created.UnsafeCursor
is now Closeable
.2023-01-07
use {}
is used with a non-local return. We introduced this performance and stability bug by not considering that non-local returns execute neither the return
nor catch
control flows.BufferedSink
and BufferedSource
. These were never intended for end-users to implement, and we're happy that Kotlin now allows us to express that in our API.synchronized
to ReentrantLock
and Condition
. We expect this to improve help when using Okio with Java virtual threads (Project Loom).2022-06-26
com.squareup.okio:okio:3.x.x
) to depend on the JVM artifact (com.squareup.okio:okio-jvm:3.x.x
) for Maven builds. This should work-around an issue where Maven doesn't interpret Gradle metadata.CipherSource
and CipherSink
to recover if the cipher doesn't support streaming. This should work around a crash with AES/GCM ciphers on Android.2022-04-19
FileSystem.SYSTEM
that are available on most Okio platforms but not all of them.ForwardingSource
is now available on all platforms.watchosX64
platform is now supported.FileSystem.openZip()
.canonicalize()
of ZIP file systems if the path doesn't exist.okio.ProtocolException
is a new exception type for multiplatform users. (It is aliased to java.net.ProtocolException
on JVM platforms).2021-10-28
This is the first stable release of Okio 3.x. This release is strongly backwards-compatible with Okio 2.x, and the new major version signifies new capabilities more than it does backwards incompatibility.
Most users should be able to upgrade from 2.x by just changing the version. If you‘re using Okio in a Kotlin Multiplatform project, you’ll need to drop the -multiplatform
suffix in your Gradle dependencies.
New: Remove @ExperimentalFileSystem
. This annotation is no longer necessary as the file system is no longer experimental!
New: Path no longer aggressively normalizes ..
segments. Use Path.normalize()
to apply these based on the content of the path, or FileSystem.canonicalize()
to do it honoring any symlinks on a particular file system.
New: Publish a bill of materials (BOM) for Okio. Depend on this from Gradle or Maven to keep all of your Okio artifacts on the same version, even if they're declared via transitive dependencies. You can even omit versions when declaring other Okio dependencies.
dependencies { api(platform("com.squareup.okio:okio-bom:3.0.0")) api("com.squareup.okio:okio") // No version! api("com.squareup.okio:okio-fakefilesystem") // No version! }
New: FileSystem.delete()
silently succeeds when deleting a file that doesn't exist. Use the new mustExist
parameter to trigger an exception instead.
New: FileSystem.createDirectories()
silently succeeds when creating a directory that already exists. Use the new mustCreate
parameter to trigger an exception instead.
New: FileSystem
offers Java-language overloads where appropriate. Previously functions that had default parameters were potentially awkward to invoke from Java.
New: Timeout.intersectWith()
returns a value instead of Unit
. This is a binary-incompatible change. We expect that this public API is very rarely used outside of Okio itself.
Fix: Change BufferedSource.readDecimalLong()
to fail if the input value is just -
. Previously Okio incorrectly returned 0
for this.
2021-10-23
okio-fakefilesystem
only.)FileMetadata.extras
can track metadata for custom FileSystem
implementations.macosArm64
, iosSimulatorArm64
, tvosSimulatorArm64
, and watchosSimulatorArm64
).FileSystem.listRecursively()
returns a Sequence
that includes all of a directory's children, and all of their children recursively. The implementation does a lazy, depth-first traversal.Path.relativeTo()
computes how to get from one path to another.Path.root
and Path.segments
. These APIs decompose a path into its component parts.FileSystem.listOrNull()
returns a directory‘s children, or null if the path doesn’t reference a readable directory.mustExist
. Use this to avoid creating a new file when your intention is to update an existing file.mustCreate
. Use this to avoid updating an existing file when your intention is to create a new file./
or \
) and temporary directory.FileHandle.write()
was broken and always appended to the end of the file.)2021-09-09
This release drops the -multiplatform
suffix on Kotlin Multiplatform artifacts. All artifacts now share the same name (like com.squareup.okio:okio:3.0.0-alpha.10
) for both Kotlin/JVM and Kotlin Multiplatform.
ResourceFileSystem
when classpath .jar
files have special characters in their paths.2021-08-01
ByteString.copyInto()
saves an allocation when extracting data from a ByteString
.FileHandle.protectedSize()
to match other abstract functions.0x1a
will be truncated prematurely.2021-07-13
FileSystem.RESOURCES
to initialize itself lazily.2021-07-12
ResourceFileSystem
to load roots eagerly. We had a bug where list()
on the root returned an empty list even if resources were present.FileHandle.reposition()
can seek on a source or sink returned by that FileHandle
.FileSystem.RESOURCES
.2021-06-01
FileHandle
supports random access reads, writes, and resizes on files. Create an instance with FileSystem.openReadOnly()
or FileSystem.openReadWrite()
.Cursor
which is obsoleted by FileHandle
. (UnsafeCursor
is still around!)ResourceFileSystem
to omit .class
files when indexing .zip
files. We expect this to lower the memory footprint of ResourceFileSystem
.@SharedImmutable
and run our test suite on a background thread.2021-04-27
ZipFileSystem
and ResourceFileSystem
to the main Okio module. These are currently JVM-only. The okio-zipfilesystem
module is no longer published.2021-04-14
-Platform.kt
.2021-04-06
NodeJsFileSystem
into its own module. Having it built-in prevented Okio from working in a browser where there's no synchronous file system API. This is in the okio-nodefilesystem
artifact.2021-03-24
Cursor
supports random access reads on a Source
.FileSystem.openZip(path)
returns a file system backed by a .zip
file. This is in the okio-zipfilesystem
artifact.2021-01-07
Path
, FileMetadata
, FileSystem
and ForwardingFileSystem
types are subject to API changes in a future release.okio-fakefilesystem
artifact.2021-01-07
HashingSource
, HashingSink
, buffer hash functions, and UnsafeCursor
on non-JVM platforms. Previously these were all JVM-only.Closeable
on Sink
and Source
on non-JVM platforms. Okio now includes a multiplatform okio.Closeable
interface and corresponding use {}
extension. Closing resources when you‘re done with them shouldn’t be JVM-only!Sink.hashingSink
and Source.hashingSource
functions that accept java.security.MessageDigest
and javax.crypto.Mac
instances. Use these when your hash function isn't built-in.ShortBufferException
in CipherSink
and CipherSource
on Android. (Android may throw a ShortBufferException
even if the buffer is not too short. We now avoid this problem!)2020-10-04
Buffer
when writing a slice of a segmented ByteString
. We had a severe bug where ByteString
instances created with snapshot()
and readByteString()
incorrectly adjusted the buffer’s size by their full length, not the length of the slice. This would have caused buffer reads to crash! We do not believe data was silently corrupted.CipherSink
and CipherSource
. Use these with javax.crypto.Cipher
to encrypt and decrypt streams of data. This is a low-level encryption API; most applications should use higher-level APIs like TLS when available.md5
, sha1()
, sha512()
, and sha256()
to common Kotlin. These are currently only available on ByteString
, multiplatform support for HashingSource
, HashingSink
, and Buffer
should come in a follow-up release. We wrote and optimized our own implementations of these hash functions in Kotlin. On JVM and Android platforms Okio still uses the platform's built-in hash functions.2020-08-17
2020-07-07
New: Pipe.cancel()
causes in-progress and future reads and writes on the pipe to immediately fail with an IOException
. The streams may still be canceled normally.
New: Enlarge Okio's internal segment pool from a fixed 64 KiB total to 64 KiB per processor. For example, on an Intel i9 8-core/16-thread machine the segment pool now uses up to 1 MiB of memory.
New: Migrate from synchronized
to lock-free when accessing the segment pool. Combined with the change above we saw throughput increase 3x on a synthetic benchmark designed to create contention.
2020-04-22
InflaterSource.readOrInflate()
is like InflaterSource.read()
, except it will return 0 if consuming deflated bytes from the underlying stream did not produce new inflated bytes.2020-03-20
2019-12-20
2019-12-11
InputStream
source is exhausted exactly at a buffer segment boundary. We had a bug where a sequence of reads could violate a buffer’s invariants, and this could result in a crash when subsequent reads encountered an unexpected empty segment.2019-12-11
InputStream
source is exhausted exactly at a buffer segment boundary. We had a bug where a sequence of reads could violate a buffer’s invariants, and this could result in a crash when subsequent reads encountered an unexpected empty segment.2019-10-04
ByteString
on Kotlin/Native which prevented freezing.2019-08-26
2019-07-29
This release changes our build from Kotlin-JVM to Kotlin-multiplatform (which includes JVM). Both native and JavaScript platforms are unstable preview releases and subject to backwards-incompatible changes in forthcoming releases.
To try Okio in a multiplatform project use this Maven coordinate:
api('com.squareup.okio:okio-multiplatform:2.3.0')
You’ll also need to enable Gradle metadata in your project's settings. The artifact name for JVM projects has not changed.
api
instead of implementation
for the kotlin-stdlib dependency.BufferedSource.peek()
.2019-04-29
BufferedSource.peek()
.2019-01-28
Pipe.fold()
close the underlying sink when necessary.2019-01-28
Pipe.fold()
close the underlying sink when necessary.2019-01-17
Pipe.fold()
flush the underlying sink.2019-01-17
Pipe.fold()
flush the underlying sink.2019-01-16
New: Throttler
limits sources and sinks to a maximum desired throughput. Multiple sources and sinks can be attached to the same throttler and their combined throughput will not exceed the desired throughput. Multiple throttlers can also be used on the same source or sink and they will all be honored.
New: Pipe.fold()
replaces the actively-readable Source
with a passively-writable Sink
. This can be used to forward one sink to a target that is initially undetermined.
New: Optimize performance of ByteStrings created with Buffer.snapshot()
.
2019-01-16
Pipe.fold()
public.2019-01-16
Pipe.fold()
to Okio 1.x.2018-10-08
BufferedSource.peek()
and BufferedSource.getBuffer()
to Okio 1.x.AsyncTimeout
sources.2018-09-22
New: BufferedSource.peek()
returns another BufferedSource
that reads ahead on the current source. Use this to process the same data multiple times.
New: Deprecate BufferedSource.buffer()
, replacing it with either BufferedSource.getBuffer()
(in Java) or BufferedSource.buffer
(in Kotlin). We have done likewise for BufferedSink
. When we introduced the new extension method Source.buffer()
in Okio 2.0 we inadvertently collided with an existing method. This fixes that.
New: Improve performance of Buffer.writeUtf8()
. This comes alongside initial implementation of UTF-8 encoding and decoding in JavaScript which uses XOR masks for great performance.
2018-08-27
This release commits to a stable 2.0 API. Read the 2.0.0-RC1 changes for advice on upgrading from 1.x to 2.x.
We‘ve also added APIs to ease migration for Kotlin users. They use Kotlin’s @Deprecated
annotation to help you change call sites from the 1.x style to the 2.x style.
2018-07-26
Okio 2 is a major release that upgrades the library's implementation language from Java to Kotlin.
Okio 2.x is binary-compatible with Okio 1.x and does not change any behavior. Classes and .jar files compiled against 1.x can be used with 2.x without recompiling.
Okio 2.x is .java source compatible with Okio 1.x in all but one corner case. In Okio 1.x Buffer
would throw an unchecked IllegalStateException
when attempting to read more bytes than available. Okio 2.x now throws a checked EOFException
in this case. This is now consistent with the behavior of its BufferedSource
interface. Java callers that don't already catch IOException
will now need to.
Okio 2.x is .kt source-incompatible with Okio 1.x. This release adopts Kotlin idioms where they are available.
Java | Kotlin | Idiom |
---|---|---|
Buffer.getByte() | operator fun Buffer.get() | operator function |
Buffer.size() | val Buffer.size | val |
ByteString.decodeBase64(String) | fun String.decodeBase64() | extension function |
ByteString.decodeHex(String) | fun String.decodeHex() | extension function |
ByteString.encodeString(String, Charset) | fun String.encode(Charset) | extension function |
ByteString.encodeUtf8(String) | fun String.encodeUtf8() | extension function |
ByteString.getByte() | operator fun ByteString.get() | operator function |
ByteString.of(ByteBuffer) | fun ByteBuffer.toByteString() | extension function |
ByteString.of(byte[], int, int) | fun ByteArray.toByteString() | extension function |
ByteString.read(InputStream, int) | fun InputStream.readByteString(Int) | extension function |
ByteString.size() | val ByteString.size | val |
DeflaterSink(Sink) | fun Sink.deflater() | extension function |
ForwardingSink.delegate() | val ForwardingSink.delegate | val |
ForwardingSource.delegate() | val ForwardingSource.delegate | val |
GzipSink(Sink, Deflater) | fun Sink.gzip() | extension function |
GzipSink.deflater() | val GzipSink.deflater | val |
GzipSource(Source) | fun Source.gzip() | extension function |
HashingSink.hash() | val HashingSink.hash | val |
HashingSource.hash() | val HashingSource.hash | val |
InflaterSink(Source) | fun Source.inflater() | extension function |
Okio.appendingSink(File) | fun File.appendingSink() | extension function |
Okio.blackhole() | fun blackholeSink() | top level function |
Okio.buffer(Sink) | fun Sink.buffer() | extension function |
Okio.buffer(Source) | fun Source.buffer() | extension function |
Okio.sink(File) | fun File.sink() | extension function |
Okio.sink(OutputStream) | fun OutputStream.sink() | extension function |
Okio.sink(Path) | fun Path.sink() | extension function |
Okio.sink(Socket) | fun Socket.sink() | extension function |
Okio.source(File) | fun File.source() | extension function |
Okio.source(InputStream) | fun InputStream.source() | extension function |
Okio.source(Path) | fun Path.source() | extension function |
Okio.source(Socket) | fun Socket.source() | extension function |
Pipe.sink() | val Pipe.sink | val |
Pipe.source() | val Pipe.source | val |
Utf8.size(String) | fun String.utf8Size() | extension function |
Okio 2.x has similar performance to Okio 1.x. We benchmarked both versions to find potential performance regressions. We found one regression and fixed it: we were using ==
instead of ===
.
Other changes in this release:
New: Add a dependency on kotlin-stdlib. Okio‘s transitive dependencies grow from none in 1.x to three in 2.x. These are kotlin-stdlib (939 KiB), kotlin-stdlib-common (104 KiB), and JetBrains’ annotations (17 KiB).
New: Change Okio to build with Gradle instead of Maven.
2018-07-18
Buffer.select()
. This improves performance when selecting among large lists of options.InterruptedIOException
.2018-02-11
Buffer.UnsafeCursor
provides direct access to Okio internals. This API is like Okio‘s version of Java reflection: it’s a very powerful API that can be used for great things and dangerous things alike. The documentation is extensive and anyone using it should review it carefully before proceeding!BufferedSource
to implement java.nio.ReadableByteChannel
and BufferedSink
to implement java.nio.WritableByteChannel
. Now it's a little easier to interop between Okio and NIO.okio
for use with the Java Platform Module System.Buffer.getByte()
to search backwards when doing so will be more efficient.InflaterSource
. Previously this class could return more bytes than requested.AsyncTimeout.sink().write()
.2017-05-12
Okio now uses @Nullable
to annotate all possibly-null values. We've added a compile-time dependency on the JSR 305 annotations. This is a provided dependency and does not need to be included in your build configuration, .jar
file, or .apk
. We use @ParametersAreNonnullByDefault
and all parameters and return types are never null unless explicitly annotated @Nullable
.
Warning: this release is source-incompatible for Kotlin users. Nullability was previously ambiguous and lenient but now the compiler will enforce strict null checks.
2017-04-11
writeUtf8CodePoint()
to emit ?
for partial surrogates. The previous behavior was inconsistent: given a malformed string with a partial surrogate, writeUtf8()
emitted ?
but writeUtf8CodePoint()
threw an IllegalArgumentException
. Most applications will never encounter partial surrogates, but for those that do this behavior was unexpected.readUtf8LineStrict()
to be limited.Utf8.size()
method to get the number of bytes required to encode a string as UTF-8. This may be useful for length-prefixed encodings.2016-10-11
Buffer.writeString()
had a major bug where it didn't respect offsets if the specified charset was UTF-8. This was because our short-circuit optimization omitted necessary offset parameters.HashingSource
, HashingSink
, ByteString
, and Buffer
. This makes it easy to create a keyed-hash message authentication code (HMAC) wherever your data is. Unlike the other hashes, HMAC uses a ByteString
secret key for authentication.ByteString.of(ByteBuffer)
makes it easier to mix NIO with Okio.2016-08-28
GzipSource
. Previously attempting to decompress such files would fail due to an overflow when validating the total length.Okio.blackhole()
returns a sink where all bytes written are discarded. This is Okio's equivalent of /dev/null
.ByteString.encodeString()
and decode strings in any charset using ByteString.string()
. Most applications should prefer ByteString.encodeUtf8()
and ByteString.utf8()
unless it's necessary to support a legacy charset.GzipSink.deflater()
makes it possible to configure the compression level.2016-07-01
Pipe
makes it easy to connect a producer thread to a consumer thread. Reads block until data is available to read. Writes block if the pipe's is full. Both sources and sinks support timeouts.BufferedSource.rangeEquals()
makes it easy to compare a range in a stream to an expected value. This does the right thing: it blocks to load the data required return a definitive result. But it won't block unnecessarily.Timeout.waitUntilNotified()
makes it possible to use nice timeout abstractions on Java's built-in wait/notify primitives.HashingSource
does large reads. There was a bug where it wasn’t traversing through the segments of the buffer being hashed. This means that HashingSource
was returning incorrect answers for any writes that spanned multiple segment boundaries.2016-05-02
BufferedSource.select(Options)
API for reading one of a set of expected values.ByteString.toString()
and Buffer.toString()
friendlier. These methods return text if the byte string is valid UTF-8.indexOf()
, startsWith()
, and endsWith()
.2016-04-10
md5()
, sha1()
, and sha256()
methods on Buffer
. Also add a sha1()
method on ByteString
for symmetry.HashingSource
and HashingSink
. These classes are Okio’s equivalent to the JDK’s DigestInputStream
and DigestOutputStream
. They offer convenient md5()
, sha1()
, and sha256()
factory methods to avoid an impossible NoSuchAlgorithmException
.ByteString.asByteBuffer()
.BufferedSource.indexOfElement()
and indexOf(ByteString)
. Previously this method had a bug that caused it to be very slow on large buffers.2015-08-25
BufferedSource.indexOf(ByteString)
searches a source for the next occurrence of a byte string.AssertionError
thrown on Android 4.2.2 and earlier when asynchronously closing a socket.2015-06-19
SocketTimeoutException
. This builds on new extension point in AsyncTimeout
to customize the exception when a timeout occurs.ByteString
now implements Comparable
. The comparison sorts bytes as unsigned: {@code ff} sorts after {@code 00}.2015-05-16
Timeout.throwIfReached()
would throw InterruptedIOException
on thread interruption, and IOException
if the deadline was reached. Now it throws InterruptedIOException
in both cases.EOFException
when attempting to read digits from an empty source. Previously this would crash with an unchecked exception.BufferedSink
can now write substrings directly, potentially saving an allocation for some callers.ForwardingTimeout
class.2015-03-16
BufferedSource
and BufferedSink
. Unlike the alternatives, these methods don’t do any memory allocations!Buffer.clone()
and Buffer.copyTo()
by sharing underlying segments between buffers.Buffer.snapshot()
returns an immutable snapshot of a buffer as a ByteString
. This builds on segment sharing so that snapshots are shallow, immutable copies.ByteString.rangeEquals()
.ByteString.md5()
and ByteString.sha256()
.ByteString.base64Url()
returns URL-safe Base64. The existing decoding method has been extended to support URL-safe Base64 input.ByteString.substring()
returns a prefix, infix, or suffix.Sink
now implements java.io.Flushable
.Buffer.write(Source, long)
now always writes fully. The previous behavior would return as soon as any data had been written; this was inconsistent with all other write() methods in the API.2014-12-30
Okio.buffer()
always buffers for better predictability.readUtf8LineStrict()
throws.Source
on zero-byte writes.2014-12-11
BufferedSink.emit()
, BufferedSource.request()
and BufferedSink.indexOfElement()
.Buffer.indexOf()
2014-08-08
read(byte[])
, read(byte[], offset, byteCount)
, and void readFully(byte[])
to BufferedSource
.Buffer
methods.2014-05-23
2014-05-03
2014-04-24
2014-04-18
2014-04-17
2014-04-15
ByteString.of(byte[] data, int offset, int byteCount)
2014-04-08