0
# Core I/O Operations
1
2
This document covers Okio's essential byte manipulation, buffered I/O, and streaming operations. These are the fundamental building blocks for all data processing in Okio.
3
4
## ByteString
5
6
ByteString represents an immutable sequence of bytes with built-in encoding, hashing, and comparison capabilities.
7
8
### Creation
9
10
```kotlin { .api }
11
// From companion object
12
val empty = ByteString.EMPTY
13
val fromBytes = ByteString.of(0x48, 0x65, 0x6c, 0x6c, 0x6f) // "Hello"
14
15
// From String extensions
16
val fromString = "Hello, Okio!".encodeUtf8()
17
18
// From ByteArray extensions
19
val bytes = byteArrayOf(0x48, 0x65, 0x6c, 0x6c, 0x6f)
20
val fromByteArray = bytes.toByteString()
21
val fromByteArrayRange = bytes.toByteString(offset = 1, byteCount = 3)
22
```
23
24
### Core Properties and Methods
25
26
```kotlin { .api }
27
expect open class ByteString internal constructor(data: ByteArray) : Comparable<ByteString> {
28
// Properties
29
val size: Int
30
operator fun get(index: Int): Byte
31
32
// Text conversion
33
fun utf8(): String
34
35
// Encoding
36
fun base64(): String
37
fun base64Url(): String
38
fun hex(): String
39
40
// Hashing
41
fun md5(): ByteString
42
fun sha1(): ByteString
43
fun sha256(): ByteString
44
fun sha512(): ByteString
45
fun hmacSha1(key: ByteString): ByteString
46
fun hmacSha256(key: ByteString): ByteString
47
fun hmacSha512(key: ByteString): ByteString
48
49
// Case conversion
50
fun toAsciiLowercase(): ByteString
51
fun toAsciiUppercase(): ByteString
52
53
// Manipulation
54
fun substring(beginIndex: Int = 0, endIndex: Int = size): ByteString
55
fun toByteArray(): ByteArray
56
fun copyInto(offset: Int = 0, target: ByteArray, targetOffset: Int = 0, byteCount: Int = minOf(size - offset, target.size - targetOffset)): Int
57
58
// Comparison and search
59
fun rangeEquals(offset: Int, other: ByteString, otherOffset: Int = 0, byteCount: Int): Boolean
60
fun startsWith(prefix: ByteString): Boolean
61
fun endsWith(suffix: ByteString): Boolean
62
fun indexOf(other: ByteString, fromIndex: Int = 0): Int
63
fun lastIndexOf(other: ByteString, fromIndex: Int = size): Int
64
65
// Comparison
66
override fun compareTo(other: ByteString): Int
67
override fun equals(other: Any?): Boolean
68
override fun hashCode(): Int
69
override fun toString(): String
70
71
companion object {
72
val EMPTY: ByteString
73
fun of(vararg data: Byte): ByteString
74
fun read(inputStream: InputStream, byteCount: Int): ByteString
75
}
76
}
77
```
78
79
### Extension Functions
80
81
```kotlin { .api }
82
// String to ByteString conversion
83
fun String.encodeUtf8(): ByteString
84
fun String.decodeBase64(): ByteString?
85
fun String.decodeHex(): ByteString
86
87
// ByteArray to ByteString conversion
88
fun ByteArray.toByteString(offset: Int = 0, byteCount: Int = size): ByteString
89
```
90
91
### Usage Examples
92
93
```kotlin
94
// Creating and manipulating ByteStrings
95
val data = "Hello, Okio!".encodeUtf8()
96
println("Size: ${data.size}") // Size: 12
97
println("Base64: ${data.base64()}") // Base64: SGVsbG8sIE9raW8h
98
println("Hex: ${data.hex()}") // Hex: 48656c6c6f2c204f6b696f21
99
100
// Hashing
101
val hash = data.sha256()
102
println("SHA-256: ${hash.hex()}")
103
104
// Substring operations
105
val hello = data.substring(0, 5) // "Hello"
106
val okio = data.substring(7, 11) // "Okio"
107
108
// Search operations
109
val commaIndex = data.indexOf(",".encodeUtf8()) // 5
110
val startsWithHello = data.startsWith("Hello".encodeUtf8()) // true
111
```
112
113
## Buffer
114
115
Buffer is a mutable collection of bytes that implements both BufferedSource and BufferedSink, providing efficient byte array pooling and segment-based storage.
116
117
### Core Buffer Operations
118
119
```kotlin { .api }
120
expect class Buffer() : BufferedSource, BufferedSink {
121
// Properties
122
var size: Long
123
override val buffer: Buffer // Returns self
124
125
// Basic operations
126
fun copyTo(out: Buffer, offset: Long = 0L, byteCount: Long): Buffer
127
fun copyTo(out: Buffer, offset: Long = 0L): Buffer // Overload for remaining bytes
128
fun completeSegmentByteCount(): Long
129
operator fun get(pos: Long): Byte
130
fun clear()
131
fun skip(byteCount: Long)
132
133
// Hashing (same as ByteString)
134
fun md5(): ByteString
135
fun sha1(): ByteString
136
fun sha256(): ByteString
137
fun sha512(): ByteString
138
fun hmacSha1(key: ByteString): ByteString
139
fun hmacSha256(key: ByteString): ByteString
140
fun hmacSha512(key: ByteString): ByteString
141
142
// Buffer management
143
fun copy(): Buffer
144
fun snapshot(): ByteString
145
fun snapshot(byteCount: Int): ByteString
146
147
// Advanced operations
148
fun readUnsafe(unsafeCursor: UnsafeCursor = UnsafeCursor()): UnsafeCursor
149
fun readAndWriteUnsafe(unsafeCursor: UnsafeCursor = UnsafeCursor()): UnsafeCursor
150
}
151
```
152
153
### UnsafeCursor for High-Performance Access
154
155
```kotlin { .api }
156
class Buffer.UnsafeCursor {
157
var buffer: Buffer?
158
var readWrite: Boolean
159
var offset: Long
160
var data: ByteArray?
161
var start: Int
162
var end: Int
163
164
fun next(): Int
165
fun seek(offset: Long): Int
166
fun resizeBuffer(newSize: Long): Long
167
fun expandBuffer(minByteCount: Int): Long
168
}
169
```
170
171
### Usage Examples
172
173
```kotlin
174
// Basic buffer operations
175
val buffer = Buffer()
176
buffer.writeUtf8("Hello")
177
buffer.writeUtf8(", ")
178
buffer.writeUtf8("Okio!")
179
180
println("Buffer size: ${buffer.size}") // 12
181
println("Content: ${buffer.readUtf8()}") // Hello, Okio!
182
183
// Copying data between buffers
184
val source = Buffer().writeUtf8("Source data")
185
val destination = Buffer()
186
source.copyTo(destination)
187
188
// Snapshot to immutable ByteString
189
val buffer2 = Buffer().writeUtf8("Test data")
190
val snapshot = buffer2.snapshot() // Creates ByteString without consuming buffer
191
```
192
193
## Source and Sink
194
195
Source and Sink are the fundamental streaming interfaces in Okio.
196
197
### Source Interface
198
199
```kotlin { .api }
200
interface Source : Closeable {
201
/**
202
* Removes at least 1, and up to byteCount bytes from this source and appends them to sink.
203
* Returns the number of bytes read, or -1 if this source is exhausted.
204
*/
205
fun read(sink: Buffer, byteCount: Long): Long
206
207
/**
208
* Returns the timeout for this source.
209
*/
210
fun timeout(): Timeout
211
212
/**
213
* Closes this source and releases the resources held by this source.
214
*/
215
override fun close()
216
}
217
```
218
219
### Sink Interface
220
221
```kotlin { .api }
222
expect interface Sink : Closeable {
223
/**
224
* Removes exactly byteCount bytes from source and appends them to this sink.
225
*/
226
fun write(source: Buffer, byteCount: Long)
227
228
/**
229
* Pushes all buffered bytes to their final destination.
230
*/
231
fun flush()
232
233
/**
234
* Returns the timeout for this sink.
235
*/
236
fun timeout(): Timeout
237
238
/**
239
* Closes this sink and releases the resources held by this sink.
240
*/
241
override fun close()
242
}
243
```
244
245
### Utility Functions
246
247
```kotlin { .api }
248
// Convert Source/Sink to buffered versions
249
fun Source.buffer(): BufferedSource
250
fun Sink.buffer(): BufferedSink
251
252
// Utility sinks
253
fun blackholeSink(): Sink
254
255
// Resource management
256
inline fun <T : Closeable?, R> T.use(block: (T) -> R): R
257
```
258
259
## BufferedSource
260
261
BufferedSource provides an efficient interface for reading data with internal buffering.
262
263
### Reading Primitives
264
265
```kotlin { .api }
266
expect sealed interface BufferedSource : Source {
267
// Buffer access
268
val buffer: Buffer
269
270
// State checking
271
fun exhausted(): Boolean
272
fun require(byteCount: Long) // Throws EOFException if not available
273
fun request(byteCount: Long): Boolean // Returns false if not available
274
275
// Byte reading
276
fun readByte(): Byte
277
fun readShort(): Short
278
fun readShortLe(): Short
279
fun readInt(): Int
280
fun readIntLe(): Int
281
fun readLong(): Long
282
fun readLongLe(): Long
283
284
// Number parsing
285
fun readDecimalLong(): Long
286
fun readHexadecimalUnsignedLong(): Long
287
288
// Skipping
289
fun skip(byteCount: Long)
290
291
// Bulk reading
292
fun readByteString(): ByteString
293
fun readByteString(byteCount: Long): ByteString
294
fun readByteArray(): ByteArray
295
fun readByteArray(byteCount: Long): ByteArray
296
297
// Array reading
298
fun read(sink: ByteArray): Int
299
fun read(sink: ByteArray, offset: Int, byteCount: Int): Int
300
fun readFully(sink: ByteArray)
301
fun readFully(sink: Buffer, byteCount: Long)
302
fun readAll(sink: Sink): Long
303
304
// String reading
305
fun readUtf8(): String
306
fun readUtf8(byteCount: Long): String
307
fun readUtf8Line(): String?
308
fun readUtf8LineStrict(): String
309
fun readUtf8LineStrict(limit: Long): String
310
fun readUtf8CodePoint(): Int
311
}
312
```
313
314
### Search and Selection Operations
315
316
```kotlin { .api }
317
expect sealed interface BufferedSource : Source {
318
// Selection
319
fun select(options: Options): Int
320
fun <T : Any> select(options: TypedOptions<T>): T?
321
322
// Search for bytes
323
fun indexOf(b: Byte): Long
324
fun indexOf(b: Byte, fromIndex: Long): Long
325
fun indexOf(b: Byte, fromIndex: Long, toIndex: Long): Long
326
327
// Search for byte strings
328
fun indexOf(bytes: ByteString): Long
329
fun indexOf(bytes: ByteString, fromIndex: Long): Long
330
fun indexOf(bytes: ByteString, fromIndex: Long, toIndex: Long): Long
331
332
// Search for any of multiple bytes
333
fun indexOfElement(targetBytes: ByteString): Long
334
fun indexOfElement(targetBytes: ByteString, fromIndex: Long): Long
335
336
// Range comparison
337
fun rangeEquals(offset: Long, bytes: ByteString): Boolean
338
fun rangeEquals(offset: Long, bytes: ByteString, bytesOffset: Int, byteCount: Int): Boolean
339
340
// Peek source (non-consuming reads)
341
fun peek(): BufferedSource
342
}
343
```
344
345
### Usage Examples
346
347
```kotlin
348
// Reading different data types
349
val source = Buffer()
350
.writeByte(42)
351
.writeInt(1234)
352
.writeUtf8("Hello")
353
354
val byte = source.readByte() // 42
355
val int = source.readInt() // 1234
356
val text = source.readUtf8() // "Hello"
357
358
// Line-based reading
359
val lines = Buffer().writeUtf8("Line 1\nLine 2\nLine 3\n")
360
while (!lines.exhausted()) {
361
val line = lines.readUtf8Line()
362
println("Read: $line")
363
}
364
365
// Selection-based reading
366
val options = Options.of("GET".encodeUtf8(), "POST".encodeUtf8(), "PUT".encodeUtf8())
367
val request = Buffer().writeUtf8("POST /api/users")
368
val method = request.select(options) // Returns 1 (index of "POST")
369
```
370
371
## BufferedSink
372
373
BufferedSink provides an efficient interface for writing data with internal buffering.
374
375
### Writing Operations
376
377
```kotlin { .api }
378
expect sealed interface BufferedSink : Sink {
379
// Buffer access
380
val buffer: Buffer
381
382
// ByteString and ByteArray writing
383
fun write(byteString: ByteString): BufferedSink
384
fun write(byteString: ByteString, offset: Int, byteCount: Int): BufferedSink
385
fun write(source: ByteArray): BufferedSink
386
fun write(source: ByteArray, offset: Int, byteCount: Int): BufferedSink
387
388
// Source writing
389
fun writeAll(source: Source): Long
390
fun write(source: Source, byteCount: Long): BufferedSink
391
392
// String writing
393
fun writeUtf8(string: String): BufferedSink
394
fun writeUtf8(string: String, beginIndex: Int, endIndex: Int): BufferedSink
395
fun writeUtf8CodePoint(codePoint: Int): BufferedSink
396
397
// Primitive writing
398
fun writeByte(b: Int): BufferedSink
399
fun writeShort(s: Int): BufferedSink
400
fun writeShortLe(s: Int): BufferedSink
401
fun writeInt(i: Int): BufferedSink
402
fun writeIntLe(i: Int): BufferedSink
403
fun writeLong(v: Long): BufferedSink
404
fun writeLongLe(v: Long): BufferedSink
405
406
// Number formatting
407
fun writeDecimalLong(v: Long): BufferedSink
408
fun writeHexadecimalUnsignedLong(v: Long): BufferedSink
409
410
// Buffer management
411
override fun flush()
412
fun emit(): BufferedSink
413
fun emitCompleteSegments(): BufferedSink
414
}
415
```
416
417
### Usage Examples
418
419
```kotlin
420
// Basic writing operations
421
val sink = Buffer()
422
sink.writeUtf8("Hello, ")
423
.writeUtf8("Okio!")
424
.writeByte(10) // newline
425
.writeInt(42)
426
.flush()
427
428
// Writing different data types
429
val data = Buffer()
430
data.writeByte(0xFF)
431
.writeShort(1234)
432
.writeInt(0x12345678)
433
.writeLong(System.currentTimeMillis())
434
.writeUtf8("Timestamp")
435
436
// Chaining operations
437
val output = Buffer()
438
.writeUtf8("HTTP/1.1 200 OK\r\n")
439
.writeUtf8("Content-Type: application/json\r\n")
440
.writeUtf8("Content-Length: 13\r\n")
441
.writeUtf8("\r\n")
442
.writeUtf8("{\"ok\": true}")
443
```
444
445
## Advanced Buffer Features
446
447
### Segment Pool Optimization
448
449
Okio uses internal segment pools to minimize memory allocations and garbage collection:
450
451
```kotlin
452
// Efficient data movement - segments are moved, not copied
453
val source = Buffer().writeUtf8("Large data chunk")
454
val destination = Buffer()
455
source.copyTo(destination) // Segments are transferred, not duplicated
456
```
457
458
### Memory-Efficient Operations
459
460
```kotlin
461
// Reading large files without loading everything into memory
462
val largeFile: Source = // ... source for large file
463
val processedData = Buffer()
464
465
largeFile.use { source ->
466
val buffered = source.buffer()
467
while (!buffered.exhausted()) {
468
val chunk = buffered.readByteString(8192) // Read 8KB chunks
469
val processed = processData(chunk)
470
processedData.write(processed)
471
}
472
}
473
```
474
475
## Error Handling
476
477
Common exceptions when working with core I/O operations:
478
479
```kotlin { .api }
480
expect open class IOException : Exception
481
expect class EOFException : IOException
482
expect class ArrayIndexOutOfBoundsException : Exception
483
```
484
485
- **EOFException**: Thrown when trying to read beyond available data
486
- **ArrayIndexOutOfBoundsException**: Thrown for invalid array access
487
- **IOException**: General I/O operation failures