0
# Source and Sink Streaming
1
2
Source and Sink are Okio's streaming I/O abstractions. Sources supply bytes while Sinks receive bytes. Their buffered variants provide convenient methods for reading and writing common data types with automatic buffering for efficiency.
3
4
## Capabilities
5
6
### Source Interface
7
8
Basic interface for reading streams of bytes.
9
10
```kotlin { .api }
11
/**
12
* Supplies a stream of bytes
13
* Similar to InputStream but simpler and more efficient
14
*/
15
interface Source : Closeable {
16
/**
17
* Reads bytes from this source into the sink buffer
18
* @param sink Buffer to read bytes into
19
* @param byteCount Number of bytes to attempt to read
20
* @return Number of bytes actually read, or -1 if exhausted
21
* @throws IOException if an I/O error occurs
22
*/
23
@Throws(IOException::class)
24
fun read(sink: Buffer, byteCount: Long): Long
25
26
/**
27
* Returns the timeout policy for this source
28
* @return The timeout instance controlling read operations
29
*/
30
fun timeout(): Timeout
31
32
/**
33
* Closes this source and releases resources
34
* @throws IOException if an error occurs during closing
35
*/
36
@Throws(IOException::class)
37
override fun close()
38
}
39
```
40
41
### Sink Interface
42
43
Basic interface for writing streams of bytes.
44
45
```kotlin { .api }
46
/**
47
* Receives a stream of bytes
48
* Similar to OutputStream but simpler and more efficient
49
*/
50
interface Sink : Closeable {
51
/**
52
* Writes bytes from the source buffer to this sink
53
* @param source Buffer containing bytes to write
54
* @param byteCount Number of bytes to write
55
* @throws IOException if an I/O error occurs
56
*/
57
@Throws(IOException::class)
58
fun write(source: Buffer, byteCount: Long)
59
60
/**
61
* Flushes any buffered bytes to the underlying sink
62
* @throws IOException if an I/O error occurs
63
*/
64
@Throws(IOException::class)
65
fun flush()
66
67
/**
68
* Returns the timeout policy for this sink
69
* @return The timeout instance controlling write operations
70
*/
71
fun timeout(): Timeout
72
73
/**
74
* Closes this sink and releases resources
75
* @throws IOException if an error occurs during closing
76
*/
77
@Throws(IOException::class)
78
override fun close()
79
}
80
```
81
82
### BufferedSource Interface
83
84
Source with internal buffering for efficient reading operations.
85
86
```kotlin { .api }
87
/**
88
* Source with an internal buffer for efficient reading
89
* Provides convenient methods for reading common data types
90
*/
91
interface BufferedSource : Source {
92
/**
93
* Internal buffer used for buffering operations
94
*/
95
val buffer: Buffer
96
97
/**
98
* Checks if this source is exhausted (no more bytes available)
99
* @return true if no more bytes can be read
100
* @throws IOException if an I/O error occurs
101
*/
102
@Throws(IOException::class)
103
fun exhausted(): Boolean
104
105
/**
106
* Ensures at least byteCount bytes are buffered
107
* @param byteCount Minimum number of bytes to buffer
108
* @throws EOFException if insufficient bytes are available
109
* @throws IOException if an I/O error occurs
110
*/
111
@Throws(IOException::class)
112
fun require(byteCount: Long)
113
114
/**
115
* Attempts to buffer at least byteCount bytes
116
* @param byteCount Number of bytes to attempt to buffer
117
* @return true if the requested bytes are available
118
* @throws IOException if an I/O error occurs
119
*/
120
@Throws(IOException::class)
121
fun request(byteCount: Long): Boolean
122
123
/**
124
* Reads and removes a single byte
125
* @return Byte value
126
* @throws EOFException if source is exhausted
127
* @throws IOException if an I/O error occurs
128
*/
129
@Throws(IOException::class)
130
fun readByte(): Byte
131
132
/**
133
* Reads and removes a 16-bit integer in big-endian format
134
* @return Short value
135
* @throws EOFException if insufficient bytes available
136
* @throws IOException if an I/O error occurs
137
*/
138
@Throws(IOException::class)
139
fun readShort(): Short
140
141
/**
142
* Reads and removes a 16-bit integer in little-endian format
143
* @return Short value
144
* @throws EOFException if insufficient bytes available
145
* @throws IOException if an I/O error occurs
146
*/
147
@Throws(IOException::class)
148
fun readShortLe(): Short
149
150
/**
151
* Reads and removes a 32-bit integer in big-endian format
152
* @return Int value
153
* @throws EOFException if insufficient bytes available
154
* @throws IOException if an I/O error occurs
155
*/
156
@Throws(IOException::class)
157
fun readInt(): Int
158
159
/**
160
* Reads and removes a 32-bit integer in little-endian format
161
* @return Int value
162
* @throws EOFException if insufficient bytes available
163
* @throws IOException if an I/O error occurs
164
*/
165
@Throws(IOException::class)
166
fun readIntLe(): Int
167
168
/**
169
* Reads and removes a 64-bit integer in big-endian format
170
* @return Long value
171
* @throws EOFException if insufficient bytes available
172
* @throws IOException if an I/O error occurs
173
*/
174
@Throws(IOException::class)
175
fun readLong(): Long
176
177
/**
178
* Reads and removes a 64-bit integer in little-endian format
179
* @return Long value
180
* @throws EOFException if insufficient bytes available
181
* @throws IOException if an I/O error occurs
182
*/
183
@Throws(IOException::class)
184
fun readLongLe(): Long
185
186
/**
187
* Reads all remaining bytes as UTF-8 string
188
* @return String representation of remaining bytes
189
* @throws IOException if an I/O error occurs
190
*/
191
@Throws(IOException::class)
192
fun readUtf8(): String
193
194
/**
195
* Reads and removes the specified number of UTF-8 bytes
196
* @param byteCount Number of bytes to read
197
* @return String representation of the bytes
198
* @throws EOFException if insufficient bytes available
199
* @throws IOException if an I/O error occurs
200
*/
201
@Throws(IOException::class)
202
fun readUtf8(byteCount: Long): String
203
204
/**
205
* Reads a UTF-8 line, ending with \n or \r\n
206
* @return String line without line terminator, or null if exhausted
207
* @throws IOException if an I/O error occurs
208
*/
209
@Throws(IOException::class)
210
fun readUtf8Line(): String?
211
212
/**
213
* Reads a UTF-8 line, requiring a line terminator
214
* @param limit Maximum line length to prevent excessive memory usage
215
* @return String line without line terminator
216
* @throws EOFException if no line terminator found within limit
217
* @throws IOException if an I/O error occurs
218
*/
219
@Throws(IOException::class)
220
fun readUtf8LineStrict(limit: Long = Long.MAX_VALUE): String
221
222
/**
223
* Skips the specified number of bytes
224
* @param byteCount Number of bytes to skip
225
* @throws EOFException if insufficient bytes to skip
226
* @throws IOException if an I/O error occurs
227
*/
228
@Throws(IOException::class)
229
fun skip(byteCount: Long)
230
231
/**
232
* Reads all remaining bytes as ByteString
233
* @return ByteString containing all remaining bytes
234
* @throws IOException if an I/O error occurs
235
*/
236
@Throws(IOException::class)
237
fun readByteString(): ByteString
238
239
/**
240
* Reads the specified number of bytes as ByteString
241
* @param byteCount Number of bytes to read
242
* @return ByteString containing the specified bytes
243
* @throws EOFException if insufficient bytes available
244
* @throws IOException if an I/O error occurs
245
*/
246
@Throws(IOException::class)
247
fun readByteString(byteCount: Long): ByteString
248
249
/**
250
* Selects from the given options, consuming the selected option from this source
251
* @param options Options containing ByteStrings to match against
252
* @return Index of the selected option, or -1 if none match
253
* @throws IOException if an I/O error occurs
254
*/
255
@Throws(IOException::class)
256
fun select(options: Options): Int
257
258
/**
259
* Selects from the given typed options, consuming the selected option from this source
260
* @param options TypedOptions containing values to match against
261
* @return The selected value, or null if none match
262
* @throws IOException if an I/O error occurs
263
*/
264
@Throws(IOException::class)
265
fun <T : Any> select(options: TypedOptions<T>): T?
266
267
/**
268
* Reads all remaining bytes into a byte array
269
* @return Byte array containing all remaining bytes
270
* @throws IOException if an I/O error occurs
271
*/
272
@Throws(IOException::class)
273
fun readByteArray(): ByteArray
274
275
/**
276
* Reads the specified number of bytes into a byte array
277
* @param byteCount Number of bytes to read
278
* @return Byte array containing the specified bytes
279
* @throws EOFException if insufficient bytes available
280
* @throws IOException if an I/O error occurs
281
*/
282
@Throws(IOException::class)
283
fun readByteArray(byteCount: Long): ByteArray
284
285
/**
286
* Creates a new source that reads a subset of bytes from this source
287
* Does not consume bytes from this source until the returned source is read
288
* @return New BufferedSource for peeking ahead
289
*/
290
fun peek(): BufferedSource
291
}
292
```
293
294
### BufferedSink Interface
295
296
Sink with internal buffering for efficient writing operations.
297
298
```kotlin { .api }
299
/**
300
* Sink with an internal buffer for efficient writing
301
* Provides convenient methods for writing common data types
302
*/
303
interface BufferedSink : Sink {
304
/**
305
* Internal buffer used for buffering operations
306
*/
307
val buffer: Buffer
308
309
/**
310
* Writes a ByteString to this sink
311
* @param byteString ByteString to write
312
* @return This sink for method chaining
313
* @throws IOException if an I/O error occurs
314
*/
315
@Throws(IOException::class)
316
fun write(byteString: ByteString): BufferedSink
317
318
/**
319
* Writes a portion of a ByteString to this sink
320
* @param byteString ByteString to write from
321
* @param offset Starting position in ByteString
322
* @param byteCount Number of bytes to write
323
* @return This sink for method chaining
324
* @throws IOException if an I/O error occurs
325
*/
326
@Throws(IOException::class)
327
fun write(byteString: ByteString, offset: Int, byteCount: Int): BufferedSink
328
329
/**
330
* Writes a byte array to this sink
331
* @param source Byte array to write
332
* @return This sink for method chaining
333
* @throws IOException if an I/O error occurs
334
*/
335
@Throws(IOException::class)
336
fun write(source: ByteArray): BufferedSink
337
338
/**
339
* Writes a portion of a byte array to this sink
340
* @param source Byte array to write from
341
* @param offset Starting position in array
342
* @param byteCount Number of bytes to write
343
* @return This sink for method chaining
344
* @throws IOException if an I/O error occurs
345
*/
346
@Throws(IOException::class)
347
fun write(source: ByteArray, offset: Int, byteCount: Int): BufferedSink
348
349
/**
350
* Writes all bytes from a source to this sink
351
* @param source Source to read all bytes from
352
* @return Number of bytes written
353
* @throws IOException if an I/O error occurs
354
*/
355
@Throws(IOException::class)
356
fun writeAll(source: Source): Long
357
358
/**
359
* Writes bytes from a source to this sink
360
* @param source Source to read bytes from
361
* @param byteCount Number of bytes to write
362
* @return This sink for method chaining
363
* @throws IOException if an I/O error occurs
364
*/
365
@Throws(IOException::class)
366
fun write(source: Source, byteCount: Long): BufferedSink
367
368
/**
369
* Writes a single byte
370
* @param b Byte value to write
371
* @return This sink for method chaining
372
* @throws IOException if an I/O error occurs
373
*/
374
@Throws(IOException::class)
375
fun writeByte(b: Int): BufferedSink
376
377
/**
378
* Writes a 16-bit integer in big-endian format
379
* @param s Short value to write
380
* @return This sink for method chaining
381
* @throws IOException if an I/O error occurs
382
*/
383
@Throws(IOException::class)
384
fun writeShort(s: Int): BufferedSink
385
386
/**
387
* Writes a 16-bit integer in little-endian format
388
* @param s Short value to write
389
* @return This sink for method chaining
390
* @throws IOException if an I/O error occurs
391
*/
392
@Throws(IOException::class)
393
fun writeShortLe(s: Int): BufferedSink
394
395
/**
396
* Writes a 32-bit integer in big-endian format
397
* @param i Int value to write
398
* @return This sink for method chaining
399
* @throws IOException if an I/O error occurs
400
*/
401
@Throws(IOException::class)
402
fun writeInt(i: Int): BufferedSink
403
404
/**
405
* Writes a 32-bit integer in little-endian format
406
* @param i Int value to write
407
* @return This sink for method chaining
408
* @throws IOException if an I/O error occurs
409
*/
410
@Throws(IOException::class)
411
fun writeIntLe(i: Int): BufferedSink
412
413
/**
414
* Writes a 64-bit integer in big-endian format
415
* @param v Long value to write
416
* @return This sink for method chaining
417
* @throws IOException if an I/O error occurs
418
*/
419
@Throws(IOException::class)
420
fun writeLong(v: Long): BufferedSink
421
422
/**
423
* Writes a 64-bit integer in little-endian format
424
* @param v Long value to write
425
* @return This sink for method chaining
426
* @throws IOException if an I/O error occurs
427
*/
428
@Throws(IOException::class)
429
fun writeLongLe(v: Long): BufferedSink
430
431
/**
432
* Writes a string as UTF-8 bytes
433
* @param string String to write
434
* @return This sink for method chaining
435
* @throws IOException if an I/O error occurs
436
*/
437
@Throws(IOException::class)
438
fun writeUtf8(string: String): BufferedSink
439
440
/**
441
* Writes a portion of a string as UTF-8 bytes
442
* @param string String to write from
443
* @param beginIndex Starting character index
444
* @param endIndex Ending character index
445
* @return This sink for method chaining
446
* @throws IOException if an I/O error occurs
447
*/
448
@Throws(IOException::class)
449
fun writeUtf8(string: String, beginIndex: Int, endIndex: Int): BufferedSink
450
451
/**
452
* Writes a UTF-8 code point
453
* @param codePoint Unicode code point to write
454
* @return This sink for method chaining
455
* @throws IOException if an I/O error occurs
456
*/
457
@Throws(IOException::class)
458
fun writeUtf8CodePoint(codePoint: Int): BufferedSink
459
460
/**
461
* Writes a long as decimal ASCII digits
462
* @param v Long value to write as decimal
463
* @return This sink for method chaining
464
* @throws IOException if an I/O error occurs
465
*/
466
@Throws(IOException::class)
467
fun writeDecimalLong(v: Long): BufferedSink
468
469
/**
470
* Writes a long as hexadecimal ASCII digits
471
* @param v Long value to write as hexadecimal
472
* @return This sink for method chaining
473
* @throws IOException if an I/O error occurs
474
*/
475
@Throws(IOException::class)
476
fun writeHexadecimalUnsignedLong(v: Long): BufferedSink
477
478
/**
479
* Emits buffered bytes to the underlying sink
480
* @return This sink for method chaining
481
* @throws IOException if an I/O error occurs
482
*/
483
@Throws(IOException::class)
484
fun emit(): BufferedSink
485
486
/**
487
* Emits complete segments to the underlying sink
488
* @return This sink for method chaining
489
* @throws IOException if an I/O error occurs
490
*/
491
@Throws(IOException::class)
492
fun emitCompleteSegments(): BufferedSink
493
}
494
```
495
496
### Options for Selection
497
498
Classes for efficient byte string selection from buffered sources.
499
500
```kotlin { .api }
501
/**
502
* An indexed set of byte strings for efficient selection
503
* Used with BufferedSource.select() for pattern matching
504
*/
505
class Options private constructor() : AbstractList<ByteString>, RandomAccess {
506
override val size: Int
507
override fun get(index: Int): ByteString
508
509
companion object {
510
/**
511
* Creates Options from a list of ByteStrings
512
* @param byteStrings ByteStrings to select from
513
* @return Options instance for selection
514
*/
515
fun of(vararg byteStrings: ByteString): Options
516
}
517
}
518
519
/**
520
* A typed set of values that may be selected from buffered sources
521
* Maps ByteString patterns to typed values
522
*/
523
class TypedOptions<T : Any> private constructor() : AbstractList<T>, RandomAccess {
524
override val size: Int
525
override fun get(index: Int): T
526
527
companion object {
528
/**
529
* Creates TypedOptions from values and an encoding function
530
* @param values Collection of values to select from
531
* @param encode Function to convert values to ByteStrings
532
* @return TypedOptions instance for typed selection
533
*/
534
inline fun <T : Any> of(
535
values: Iterable<T>,
536
encode: (T) -> ByteString
537
): TypedOptions<T>
538
}
539
}
540
```
541
542
### Creating Buffered Sources and Sinks
543
544
Utility functions for creating buffered sources and sinks.
545
546
```kotlin { .api }
547
/**
548
* Wraps a Source with buffering
549
* @return BufferedSource that buffers reads from this source
550
*/
551
fun Source.buffer(): BufferedSource
552
553
/**
554
* Wraps a Sink with buffering
555
* @return BufferedSink that buffers writes to this sink
556
*/
557
fun Sink.buffer(): BufferedSink
558
559
/**
560
* Creates a sink that discards all bytes written to it
561
* @return Sink that ignores all data
562
*/
563
fun blackholeSink(): Sink
564
565
/**
566
* Execute block then close this resource. This will be closed even if block throws.
567
* This is similar to Java's try-with-resources but more concise.
568
* @param block Function to execute with this resource
569
* @return Result of executing the block
570
* @throws Exception any exception thrown by block or during closing
571
*/
572
inline fun <T : Closeable?, R> T.use(block: (T) -> R): R
573
```
574
575
**Usage Examples:**
576
577
```kotlin
578
// Basic source/sink usage
579
val buffer = Buffer()
580
val source: Source = buffer
581
val sink: Sink = buffer
582
583
// Write data
584
sink.write(Buffer().writeUtf8("Hello"), 5)
585
sink.flush()
586
587
// Read data
588
val readBuffer = Buffer()
589
val bytesRead = source.read(readBuffer, 1024)
590
println(readBuffer.readUtf8())
591
592
// Buffered operations
593
val bufferedSource = source.buffer()
594
val line = bufferedSource.readUtf8Line()
595
val number = bufferedSource.readInt()
596
597
val bufferedSink = sink.buffer()
598
bufferedSink.writeUtf8("Hello World")
599
.writeInt(42)
600
.writeLong(123456789L)
601
.flush()
602
603
// Resource management with use
604
FileSystem.SYSTEM.source("/tmp/file.txt".toPath()).use { source ->
605
val bufferedSource = source.buffer()
606
return bufferedSource.readUtf8()
607
}
608
609
// Chaining use with buffer
610
FileSystem.SYSTEM.sink("/tmp/output.txt".toPath()).buffer().use { sink ->
611
sink.writeUtf8("Hello World")
612
sink.writeInt(42)
613
}
614
615
// Using Options for selection
616
val options = Options.of("GET".encodeUtf8(), "POST".encodeUtf8(), "PUT".encodeUtf8())
617
val buffer = Buffer().writeUtf8("POST /api/users")
618
val selected = buffer.select(options)
619
when (selected) {
620
0 -> println("GET request")
621
1 -> println("POST request") // This will be selected
622
2 -> println("PUT request")
623
-1 -> println("No match")
624
}
625
626
// Using TypedOptions for typed selection
627
enum class HttpMethod { GET, POST, PUT }
628
val typedOptions = TypedOptions.of(
629
listOf(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT)
630
) { it.name.encodeUtf8() }
631
val method = buffer.select(typedOptions)
632
println("Selected method: $method")
633
```