Hi, In message "Re: IO#clone and 1.6 -> 1.8 question" on 03/09/09, dblack / superlink.net <dblack / superlink.net> writes: |> It's combination of the two: |> |> * file position is shared among IO clones. It's defined stdio |> behavior. | |That's what I was expecting, but: | | fh = File.new("nums") | fd = fh.clone | fh.gets | puts fh.pos | puts fd.pos | | => | 2 | 0 Ah, I have to tell you something. There's two file positions for an IO. One is a file position for a file descriptor. This is shared among duped file descriptors. The other is a file descriptor for a stdio (i.e. FILE*), this is *not* shared. For example, say we name the former position as rpos (stands for real position), and the latter as bpos (stands for buffered position). When you have "1\n2\n3\n" in a file "num", and you get an IO by opening it. fh = File.new("nums") Its rpos and bpos are 0. You clone fh. fd = fh.clone Naturally, clone's rpos and bpos are 0 too. Then you call gets on the original IO. fh.gets It returns "1\n", bpos is right after the first newline, but rpos is at the end of file, since whole file is read in the fh's buffer. puts fd.pos "pos" method returns IO's bpos, so that it returns 0. When you try to read from fd, since its internal buffer is empty, it tries to read from the file descriptor. Its rpos is at the end of file (remember rpos is shared). Thus "gets" returns nil. Weird? I agree, but it's how stdio defined to work. So what this means? It means mixing buffered read with shared file descriptor cause real confusion, just like the one you face. Do not use buffered read with IO clones. Use sysread if you want to work with IO clones. matz.