<?xml version="1.0" encoding="windows-1252"?>
<node id="350948" title="Re: Streaming to Handles (iterator)" created="2004-05-05 19:26:12" updated="2005-06-21 02:33:41">
<type id="11">
note</type>
<author id="22609">
tye</author>
<data>
<field name="doctext">
&lt;p&gt;
You don't need a stream; you want an iterator (yes, similar term).  To turn this into an iterator in Perl5, you need to keep your own "stack".  That is easy to do with an anonymous array (or two) inside your object.
&lt;/p&gt;&lt;p&gt;
I put file names that I have yet to output into &lt;code&gt;@{ $self-&gt;{files} }&lt;/code&gt; and output the next one from there the next time the iterator is called.  I put directory names that I have yet to read the list of files from into &lt;code&gt;@{ $self-&gt;{dirs} }&lt;/code&gt; and when there aren't any more file names to return, I read the next directory.
&lt;/p&gt;&lt;p&gt;
First, here is how you'd use my iterator:
&lt;/p&gt;&lt;code&gt;
#!/usr/bin/perl
use strict;
use warnings;

require List;

my $f= List-&gt;new( @ARGV );

my $file;
while(  $file= $f-&gt;next()  ) {
    print "$file\n";
}
&lt;/code&gt;&lt;p&gt;
And here is the code that implements it:
&lt;/p&gt;&lt;code&gt;
package List; # Terrible name
use strict;
use warnings;

use Cwd qw( cwd );
require File::Spec;

use vars qw( $VERSION );
$VERSION = '0.99';

sub new {
    my( $class, $path )= @_;
    my $self= { };
    if(  defined $path  ) {
        $self-&gt;look_in( $path );
    }
    bless $self, $class;
    return $self;
}

sub look_in {
    my( $self, $path )= @_;
    $path= cwd()   unless  @_ &gt; 1;
    $path= File::Spec-&gt;canonpath($path);
    $self-&gt;{path}= $path;
    $self-&gt;{dirs}= [$path];
    $self-&gt;{files}= [];
}

sub next {
    my( $self )= @_;

    while( 1 ) {
        if(  @{ $self-&gt;{files} }  ) {
            my $file = shift @{ $self-&gt;{files} };
            if(  -d $file  ) {
                push @{ $self-&gt;{dirs} }, $file;
            }
            return $file;
        }
        if(  ! @{ $self-&gt;{dirs} }  ) {
            return;
        }
        my $dir= shift @{ $self-&gt;{dirs} };
        if(  opendir( DIR, $dir )  ) {
            $self-&gt;{files}= [
                map {
                    File::Spec-&gt;catfile( $dir, $_ );
                } File::Spec-&gt;no_upwards( readdir(DIR) )
            ];
            closedir DIR;
        } else {
            warn "opendir failed, $dir: $!\n";
        }
    }
}

1;
&lt;/code&gt;&lt;p&gt;
I tested it enough to see that it appears to work just fine.
&lt;/p&gt;&lt;p&gt;
If you had directories with huge numbers of files directly in them (not in subdirectories), then you might want to make the iterator a bit more complicated such that you don't keep a list of file names and instead return each file name (almost) immediately after you get it back from [readdir] (but I'm not sure I would recommend that).
&lt;/p&gt;
&lt;div class="pmsig"&gt;&lt;div class="pmsig-22609"&gt;&lt;p align="right"&gt;
- [tye]&lt;tt&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/tt&gt;
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</field>
<field name="root_node">
349582</field>
<field name="parent_node">
349582</field>
</data>
</node>
