2009-03-23 6 views
12

Sie erhalten entweder ein Objekt IO::File oder ein Typeglob (\*STDOUT oder Symbol::symbol_to_ref("main::FH")); Wie würdest du herausfinden, ob es ein Lese- oder Schreib-Handle ist? Die Schnittstelle kann nicht erweitert werden, um diese Information zu übergeben (Ich überschreibe close, um Anrufe zu flush und sync vor dem eigentlichen Schließen hinzuzufügen).Wie kann ich feststellen, ob ein Perl-Datei-Handle ein Lese- oder Schreib-Handle ist?

Derzeit bin ich versucht zu flush und sync die Dateikennung und ignoriert den Fehler "Invalid argument" (das ist, was ich, wenn ich zu flush oder sync ein Lesehandle versuchen):

eval { $fh->flush; 1 } or do { 
     #this seems to exclude flushes on read handles 
     unless ($! =~ /Invalid argument/) { 
       croak "could not flush $fh: $!"; 
     } 
}; 

eval { $fh->sync; 1 } or do { 
     #this seems to exclude syncs on read handles 
     unless ($! =~ /Invalid argument/) { 
       croak "could not sync $fh: $!"; 
     } 
}; 
+0

+1 Fantastische Frage! Ich habe keine Ahnung, wann ich das jemals benutzen würde, aber ich bin fasziniert zu wissen, dass jemand das braucht. – scraimer

+0

Ext4 hat Probleme gebracht, die Ext3 für eine Weile versteckt gehalten hatte. Siehe http://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/ und der laufende p5p-Thread (http://www.xray.mpe.mpg.de/mailing-lists) /perl5-porters/2009-03/msg00322.html) für den Hintergrund. –

Antwort

7

Werfen Sie einen Blick auf die fcntl Optionen. Vielleicht F_GETFL mit O_ACCMODE.

Edit: habe ich ein wenig googeln und Spiele über das Mittagessen und hier einig wahrscheinlich nicht tragbarer Code aber es funktioniert für meine Linux-Box, und wahrscheinlich jedes Posix-System (vielleicht sogar Cygwin, wer weiß?) .

use strict; 
use Fcntl; 
use IO::File; 

my $file; 
my %modes = (0 => 'Read only', 1 => 'Write only', 2 => 'Read/Write'); 

sub open_type { 
    my $fh = shift; 
    my $mode = fcntl($fh, F_GETFL, 0); 
    print "File is: " . $modes{$mode & 3} . "\n"; 
} 

print "out\n"; 
$file = new IO::File(); 
$file->open('> /tmp/out'); 
open_type($file); 

print "\n"; 

print "in\n"; 
$file = new IO::File(); 
$file->open('< /etc/passwd'); 
open_type($file); 

print "\n"; 

print "both\n"; 
$file = new IO::File(); 
$file->open('+< /tmp/out'); 
open_type($file); 

Beispiel Ausgabe:

$ perl test.pl 
out 
File is: Write only 

in 
File is: Read only 

both 
File is: Read/Write 
+0

Es sieht so aus, als ob fcntl OS-spezifisch ist, aber wenn es für ein bestimmtes Betriebssystem funktioniert, kann ich einfach einen Dispatch-Hash basierend auf dem Betriebssystem erstellen und auf meinen aktuellen Code zurückgreifen, wenn das aktuelle Betriebssystem nicht im Dispatch-Hash ist. –

+0

Froh, dass es Ihnen gefällt. Ich habe einen Testcode angelegt. – JasonSmith

+0

Anstelle der harten Codierung "3" könnten Sie 'O_RDONLY | O_RDWR | O_WRONLY, aber diese Konstanten sind sehr unwahrscheinlich, da sie sich seit 20 Jahren nicht geändert haben. Trotzdem macht es den Code lesbarer. – JasonSmith