#853 InStream::readChars

liamstask Mon 7 Dec 2009

It feels like I must be missing where in the API this exists, but I'm looking for a way to create a Str from a Buf which contains my null-terminated Str values. I'm currently using InStream.readStrToken() but I hate to think of it checking each character for the terminating token when I already know how many bytes I'd like to pull out.

I can of course do InStream.readBuf() but I can't seem to find a nice way to generate a Str from a Buf, which seems a little strange.

Any tips? Thanks!

brian Mon 7 Dec 2009

You can use sys::Buf.in to perform any I/O you want off a buf, plus almost all the InStream and OutStream methods are provided as convenience:

fansh> Buf().printLine("abc").flip.readAllStr
abc

Just remember that Buf works strictly in terms of bytes with some configurable charset (which defaults to UTF-8)

liamstask Mon 7 Dec 2009

Thanks for the quick response.

In that case, if I understand correctly, all the remaining data in the InStream will be extracted as Str, whereas there's plenty of remaining data in there that will not be part of the Str I'm interested in.

Is there a way to read just part of an InStream as a Str?

brian Mon 7 Dec 2009

It depends on how you are breaking up bytes into chars:

  • if reading n bytes, then do readBuf(null, n).readAllStr (you are calling readAllStr on temp Buf, not the whole InStream)
  • if parsing by line use readLine or eachLine
  • use sys::InStream.readStrToken

liamstask Mon 7 Dec 2009

Gotcha - it looks like readBufFully() is the API you sketched out there. It's not too big a deal, but having to block until all the data I asked for is received, without being able to specify a timeout feels slightly weird.

Otherwise, just using readBuf() I actually need to supply a Buf, but that's pretty OK since I know how big to make it and won't be too wasteful, etc. which looks something like:

b := Buf(expectedLen)
this.in.readBuf(b, b.capacity)
val := b.flip().readAllStr()

I realize that it's a little ridiculous to be complaining about an extra couple lines to extract this data, but with all the other tasty one-liners afforded by the API I figured I must be missing something! Obviously between these options, something will work nicely.

brian Mon 7 Dec 2009

Yeah, I forgot that readBuf returns an Int rather than the Buf, so it makes a one liner tricky.

Maybe what we really need is something which mimics readBuf and readBufFully with char data?

virtual Int? readBuf(Buf buf, Int n)
Buf readBufFully(Buf? buf, Int n)

virtual Int? readStrBuf(StrBuf buf, Int n)
StrBuf readStrBufFully(StrBuf? buf, Int n)

What does everything think about those enhancements?

liamstask Tue 8 Dec 2009

Those sound pretty nice and consistent to me.

DanielFath Tue 8 Dec 2009

They seem right. This is InStream, right?

brian Tue 8 Dec 2009

Promoted to ticket #853 and assigned to brian

brian Tue 8 Dec 2009

Renamed from Str direct from Buf? to InStream::readStrBuf, readStrBufFully

brian Fri 18 Dec 2009

Renamed from InStream::readStrBuf, readStrBufFully to InStream::readChars

brian Fri 18 Dec 2009

Ticket resolved in 1.0.48

I added a new method:

**
** Read the next n chars from the stream as a Str using the
** current `charset`.  Block until exactly n chars have been
** read or throw IOErr if end of stream is reached first.
**
Str readChars(Int n)

A convenience also added to Buf.

The original idea of reading available chars into a StrBuf is problematic to deal with async availability when reading multiple-byte charsets. Having "read fully" semantics is consistent with all the other text based I/O.

liamstask Sat 19 Dec 2009

Great - thanks!

Login or Signup to reply.