ThirtySecondNoob has asked for the wisdom of the Perl Monks concerning the following question:

I've been having some trouble managing with filehandlers - specifically with an if statement and putting in a line of data into files. I want to dynamically name my files with date stamps from the data lines I'm getting. So far, I've been trying to use *typeglob variables with filehandlers.

I know there's an error in the code, but what I want is to find a better way of dynamically naming my files. I found some information on dereferencing filehandlers, but I don't know how to implement that in this case. Does anyone have any suggestions?

while(1) { #get line of code $new_line #get line's date stamp $line_time #if file doesnt exist create it if (! -e $DATA_DIRECTORY.$filename.".ascii") { if (tell(CURRENT_FILE) != -1) {$file = $fileholder[0]; close CURRENT_FILE; } else {print "File cant be closed bc hasnt been made yet\n";} #open this file open(CURRENT_FILE, ">>$DATA_DIRECTORY".$line_time.".ascii") || print "$line_time.ascii could not be created\n"; $fileholder[0] = *CURRENT_FILE; $file = $fileholder[0]; #add line to $NEW_FILE print $file $new_line."\n" || print "data COULDNT be printed to CURR +ENT_FILE\n"; } else { #write to file and send $file = $fileholder[0]; print $file $new_line; #need a typeglob or it wont print b/c CURRENT +_FILE is local } } #end of while loop

Replies are listed 'Best First'.
Re: dynamic filehandlers - how to deal?
by jethro (Monsignor) on Oct 08, 2010 at 01:12 UTC

    You seem to want to write lines with the same time stamp to the same file, right? And when a line has a new date you need to close the old file and open the new one, right?

    If that is the case, just remember the time of the previous line. If that is different than that of the new line, open a new file. And since opening with '>>' also creates a file you don't have to test for existence of the file.

    my $previous_time=''; while (1) { #get line of code $new_line #get line's date stamp $line_time if ($line_time ne $previous_time) { close(CURRENT_FILE) if ($previous_time); #could be left out since +opening a new file closes the old open(CURRENT_FILE, ">>$DATA_DIRECTORY".$line_time.".ascii") or die "$line_time.ascii could not be created\n"; $previous_time= $line_time; } print CURRENT_FILE $new_line: }

      Thanks to both of you guys - you really know your stuff! Jethro, you nailed it right on the money there, and roboticus, that was a good assumption not to be limited to the number of files being open at a time, although in this case the data comes in as real time. Both of these are great to work with and have tricks that I would do well to remember.

      Thanks again!

Re: dynamic filehandlers - how to deal?
by aquarium (Curate) on Oct 08, 2010 at 03:38 UTC
    If you make the open/write/close fairly atomic, i.e. not spread throughout code but a single function, you can simply open a file for append and write to it and close. if the file doesn't exist it will get created, and if exists it will be appended to. make sure to close just after the write.
    the hardest line to type correctly is: stty erase ^H
Re: dynamic filehandlers - how to deal?
by roboticus (Chancellor) on Oct 08, 2010 at 12:26 UTC

    ThirtySecondNoob:

    You're not that far off with your attempt. You're going through a few unnecessary steps to check whether the file is open and for storing the file handle, though. I've cleaned up your example a little, here (usual disclaimers apply):

    my $prev_file_name; my $file; while(1) { my $new_line = get_line_of_code(); my $line_time = get_date_stamp($new_line); my $file_name = "$DATA_DIRECTORY$line_time.ascii"; if (defined($prev_file_name) and $prev_file_name != $file_name) { close($file) if defined $file; open $file, '>>', $file_name or print "$file_name could not be created\n"; } #add line to $NEW_FILE print $file $new_line."\n" or print "data COULDNT be printed to CURRENT_FILE\n"; # This bit seems to be related to code you've pruned from # your example... #} else { # #write to file and send # $file = $fileholder[0]; # print $file $new_line; #} } #end of while loop

    While going through your example, though, I feel it's possible you may have trimmed a bit too much from it. In case you wanted to keep several different files open at once (such as for processing interleaved requests), you might want something like this:

    my $MAX_FILES=10; # Max open files we want my %files; # We can keep multiple file handles while(1) { my $new_line = get_line_of_code(); my $line_time = get_date_stamp($new_line); my $file_name = "$DATA_DIRECTORY$line_time.ascii"; if (!exists $files{$file_name}) { # close a file if we have too many my @filenames = keys %files; if (@filenames >= $MAX_FILES) { my $t = $files{$filenames[0]}; close $t or die $!; delete $files{$filenames[0]}; } open $files{$file_name}, '>>', $filename or print "$file_name could not be created\n"; } $file = $files{$file_name}; print $file $new_line."\n" or print "data COULDNT be printed to CURRENT_FILE\n"; } #end of while loop

    ...roboticus