How to Know If an Io Is Empty Without Reading It

How can I know if an IO is empty without reading it?

That's a purpose of IO::select method:

Updated example after question edited:

require 'open3'

select_timeout = Rational(1,10) # optional

Open3.popen3('ls /') do
|stdin, stdout, stderr, w_thread|

rdin, rdout, rderr = IO.select([stdin], [stdout], [stderr], select_timeout)
if rdin
p 'no data on standard input' unless rdin.member? stdin
p 'no data on standard output' unless rdout.member? stdout
p 'no data on standard error' unless rderr.member? stderr
else
p 'none of streams has data available'
end

retval = w_thread.value
end
# "no data on standard output"
# "no data on standard error"

Whereas only standard input contains data from spawned thread command ls /

How can I check if an InputStream is empty without reading from it?

I think you are looking for inputstream.available(). It does not tell you whether its empty but it can give you an indication as to whether data is there to be read or not.

How to correctly check io.Reader for nil?

To check if an io.Reader (or any other interface) value is nil, you simply compare it to nil.

Whether a non-nil io.Reader is a meaningful implementation, that's another question.

E.g. is this implementation meaningful?

type panicReader struct{}

func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}

panicReader certainly implements io.Reader, but whenever you call its Read() method, it will always panic.

There is bytes.Buffer. A pointer to it implements io.Reader. But calling Buffer.Read() on a nil *bytes.Buffer pointer value will panic. But not because you can't call methods on nil pointer receivers, but because the implementation of bytes.Buffer.Read() tries to dereference the pointer receiver, and this dereference operation is what causes the panic:

// Excerpt from bytes.Buffer.Read implementation 
func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.empty() {
// ...
}

You can't make a general conclusion here (just yet). See this io.Reader implementation:

type myBuffer struct{}

var count int

func (*myBuffer) Read(p []byte) (int, error) {
if len(p) > 0 {
count++
if count >= 10 {
return 0, io.EOF
}
p[0] = 'a'
return 1, nil
}
return 0, nil
}

*myBuffer implements io.Reader, and its Read() method does not use the pointer receiver value. What does this mean? You can call Read() on a nil *myBuffer value:

var data *myBuffer

request := &Request{
Body: data,
}

if request.Body != nil {
data, err := ioutil.ReadAll(request.Body)
fmt.Println(string(data), err)
}

This will output (try it on the Go Playground):

How to Know If an Io Is Empty Without Reading Ita <nil>

So the conclusion is this: usually types that have methods with pointer receiver require a non-nil pointer because they use the pointed object (in case of bytes.Buffer they use the fields of the pointed struct). To use such types (to have a meaningful implementation of implemented interfaces), you often need a non-nil pointer value for the methods to "work". This–however–is not always a requirement as the above myBuffer implementation shows. It's your job to always read the documentation of the used types and methods to avoid such misuses (e.g. trying to use a nil *bytes.Buffer).

See related question:

Hiding nil values, understanding why Go fails here

Go reflection with interface embedded in struct - how to detect "real" functions?

How to check potentially empty stdin without waiting for input?

The POSIX I/O functions that ultimately underlie Python's file objects have two different modes, blocking and non-blocking, controlled by a flag named O_NONBLOCK. In particular, the read function says:

When attempting to read a file … that … has no data currently available … If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].

In Python, this flag is available in the os module.


sys.stdin is already open, so you can't just pass O_NONBLOCK to the os.open function, so… what do you do? Well, you actually might want to open /dev/tty instead; it kind of depends on what you're actually doing. In that case, the answer is obvious. But let's assume that you don't. So, you want to change the flags of the already-open file. That's exactly what fcntl is for. You use the F_GETFL operation to read the current flags, or in the bit for O_NONBLOCK, and F_SETFL the result. You can remember the current flags for later if you want to restore things, of course.

In Python, the fcntl function, and the operation constants, are available in the fcntl module.


One last problem: sys.stdin isn't a raw file object, it's a TextIOWrapper that does Unicode decoding on top of a BufferedReader, which itself adds buffering on top of a FileIO. So, sys.stdin.read() isn't directly calling the POSIX read function. In order to do that, you need to use sys.stdin.buffer.raw. And you may also need to do lots of careful flushing if you want to go back and forth between raw and normal input. (Note that this means you're giving up Unicode and instead getting a single-byte bytes object, which could be, say, half of a UTF-8 character or a quarter of a terminal escape character. Hopefully you're expecting that.)


Now, what does FileIO.read return when nothing is available? Well, it's an implementation of RawIOBase, and RawIOBase.read says:

If 0 bytes are returned, and size was not 0, this indicates end of file. If the object is in non-blocking mode and no bytes are available, None is returned.

In other words, you're going to get None if nothing is available, b'' for EOF, or a single-byte bytes for anything else.


So, putting it all together:

old_settings = termios.tcgetattr(fd)
old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
try:
tty.setraw(fd)
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags | os.O_NONBLOCK)
return sys.stdin.buffer.raw.read(1)
finally:
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags)
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

One last thing: Is there a way to tell if input is ready without reading it? Yes, but not portably. Depending on your platform, select, poll, epoll, and/or kqueue may be available and may work on regular files. read(0) may be guaranteed to return b'' instead of None. And so on. You can read your local man pages. But a simpler solution is the same thing C's stdio does: add a 1-byte-max buffer, and use it to implement your own read and peek or read and unread wrappers.

How to return a empty io.Reader?

In case of a non-nil error return value, usually other parameters are left to the zero value of their type, which in case of io.Reader (which is an interface type) should be nil:

return nil, err

Callers are responsible to first always check the returned error, and only proceed to use other return values if the error is nil. This is the general "rule". There may be exceptions of course, in which case you should document the deviant behavior.

Actually there's nothing wrong with providing other values along with non-nil errors, and often it's useful. Typical example is the io.Reader.Read() method, which documents how implementations should (must) work:

It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.

... When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read.

So even if Reader.Read() returns a non-nil error, it also reports how many bytes it was able to read successfully before the error was encountered, so you may process / use up to n bytes from the slice.

How to check whether a file is empty or not

>>> import os
>>> os.stat("file").st_size == 0
True

How can I know text file is empty or not?(in C)

If the file was successfully open for read, as per fopen(filename, "r"), you can verify if it is empty before any read operation this way:

int is_empty_file(FILE *fp) {
int c = getc(fp);
if (c == EOF)
return 1;
ungetc(c, fp);
return 0;
}

ungetc() is guaranteed to work for at least one character. The above function will return 1 if the file is empty or if it cannot be read, due to an I/O error. You can tell which by testing ferr(fp) or feof(fp).

If the file is a stream associated to a device or a terminal, the test code will block until at least one byte can be read, or end of file is signaled.

If the file is a regular file, you could also use a system specific API to determine the file size, such as stat, lstat, fstat (on Posix systems).



Related Topics



Leave a reply



Submit