1
/
5

部分読み取り・部分書き込みを許す言語とそうでない言語

Photo by Katie Jowett on Unsplash

Goの入出力コードをレビューしていて気付いたのですが、世の中には部分読み取り・部分書き込みを許す(ような標準ライブラリを持つ)言語とそうではない言語があるようです。そこでどのような言語が部分読み取り・部分書き込みを許しているか軽く調査しました。

部分読み取り・部分書き込みとは

「最大1024バイトの読み取り」を要求したときに、入力の終端でもエラーでもないのに20バイトしか返ってこなかった、というような状況を部分読み取り (partial read) といいます。

「456バイトの書き込み」を要求したときに、エラーでないにもかかわらず300バイトしか書き込まれなかった、というような状況を部分書き込み (partial write) といいます。

入出力APIによって、部分読み取り・部分書き込みを許すものとそうでないものがあるようです。 (利用者にとっては、部分読み取り・部分書き込みが許されないほうが話が簡単です)

C: read(2) / write(2)

部分読み取り・部分書き込みがありえる

It is not an error if this number is smaller than the number of bytes requested;

https://man7.org/linux/man-pages/man2/read.2.html

Note that a successful `write()` may transfer fewer than count bytes.

https://man7.org/linux/man-pages/man2/write.2.html

Open Groupではread(2)の部分読み取りはありえる一方、write(2)の部分書き込みはFIFOや通常ファイルに関しては起きないことになっている: https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.htmlhttps://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html

C: fread(3) / fwrite(3)

完全読み取り・完全書き込みのみ

Upon successful completion, `fread()` shall return the number of elements successfully read which is less than nitems only if a read error or end-of-file is encountered.

https://man7.org/linux/man-pages/man3/fread.3p.html

The `fwrite()` function shall return the number of elements successfully written, which may be less than nitems if a write error is encountered.

https://man7.org/linux/man-pages/man3/fwrite.3p.html

Rust: Read::read / Write::write

部分読み取り・部分書き込みがありえる

It is not an error if the returned value `n` is smaller than the buffer size, even when the reader is not at the end of the stream yet.

https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read

    // Writes some prefix of the byte string, not necessarily all of it.
buffer.write(b"some bytes")?;

https://doc.rust-lang.org/stable/std/io/trait.Write.html#tymethod.write

完全読み取り・完全書き込みをするための read_exact / write_all ユーティリティーが別途提供されています。

Go: io.Reader / io.Writer

  • 部分読み取りがありえる
  • 完全書き込みのみ
If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.

https://golang.org/pkg/io/#Reader

Write must return a non-nil error if it returns n < len(p).

https://golang.org/pkg/io/#Writer

Java: InputStream / OutputStream

完全読み取り・完全書き込みのみ

This method blocks until input data is available, end of file is detected, or an exception is thrown.

https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/io/InputStream.html#read(byte%5B%5D,int,int)

書き込みは戻り値自体がない

public void write​(byte[] b, int off, int len) throws IOException

https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/io/OutputStream.html#write(byte%5B%5D,int,int)

まとめと考察

  • Linuxの read(2), write(2) は部分読み取り・部分書き込みを許す (Open Groupの write(2) は部分書き込みに制約がある)
  • RustのRead / Writeは部分読み取り・部分書き込みを許す
  • Goのio.Readerは部分読み取りを許すが、io.Writerは完全書き込みのみ

これには以下のような事情があるのではないかと思います。

  • read(2) / write(2) はI/O多重化と組み合わせることがあるため、ブロッキングのない範囲内でのI/O操作をサポートしたい。
  • Rustはシステムプログラミング言語として、上記のような低層APIをそのまま扱えるようにしたい。
  • Goはそれ自体が非同期ランタイムを持つため、プログラマーに提供するAPIはI/O多重化を想定する必要がない。
  • 入力ストリームはユーザー起因でブロックすることがあるため、きりのよい所まで読み取れるほうが望ましい場合がある。そのため、Goなどでは部分読み取りのみ許している。
Wantedly, Inc.'s job postings
8 Likes
8 Likes

Weekly ranking

Show other rankings
If this story triggered your interest, go ahead and visit them to learn more