'How do I open a file only if it already exists?

This is what I am trying to achieve:

open(my $file,">>","/var/opt/input.txt");
if("/var/opt/input.txt" is opened sucessfully)
{
  do some tasks;
}
else
{
  do some other task;
}


Solution 1:[1]

So you want to open a file for appending but only if it already exists (so not create it).

One way is indeed to first check whether the file (doesn't) exist and then open it. However, then there is a race condition since the file can be created right after it's been checked! A rare thing to happen, mostly, but having a race condition is no good and always has to be avoided as it can lead to quiet and mysterious bugs.

This requirement is a good example of what sysopen is for, when one needs more detailed control and flexibility. To directly do exactly what is needed

use Fcntl qw(O_WRONLY O_APPEND);  # to bring in symbolic constants

if ( sysopen(my $fh, $filename, O_WRONLY | O_APPEND) ) {  # fails if no file
    say $fh scalar localtime;                             # appends to file
}
elsif ($!{ENOENT}) {
    # The case to avoid, file doesn't exist ($!: "No such file or directory")
    warn "Can't sysopen $filename: $!";  
}
else { 
    # Some other error
    warn "Can't sysopen $filename: $!";
}

With the given combination of flags the open call fails if the file doesn't already exist. Any file-open may fail in other ways as well so I separate the check for the absence of the file as the reason for failure (using %! hash). If that's excessive for your need just use one else and print $! from it .

If this is in a module remember to use carp for a warning instead (need use Carp; for that)

See sysopen and its section in perlopentut, as well as the useful Fcntl

Solution 2:[2]

As others have pointed out open() returns a true or false value which indicates whether the file was opened successfully. However, it's a standard file-handling feature that if you try to open a file for writing (or appending) that doesn't already exist, then the file is created for you. And it sounds like that isn't what you want.

So you need to check whether the file exists before you try to open it. Perl has a number of file test operators that help you with that. You can use -f which checks that a file exists.

my $file_name = '/var/opt/input.txt';

if (-f $file_name and open my $file, '>>', $file) {
  # File exists and was opened successfully
} else {
  # Either file doesn't exist or file can't be opened
}

You could also split it into two separate tests.

my $file_name = '/var/opt/input.txt';

if (-f $file_name) {
  if (open my $file, '>>', $file) {
    # File exists and was opened successfully
  } else {
    # File exists but can't be opened
  }
} else {
  # File doesn't exist
}

Solution 3:[3]

Note: This answers the original question "How to check if open() subroutine call gave a successful result in the Perl". The question was modified several times after I posted this answer.


From the documentation for open:

Open returns nonzero on success, the undefined value otherwise.

One way is to directly use open in the if clause:

if (open(my $file, ">>", "input.txt"))
{
  #do some tasks;
}
else
{
  #do some other task;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dave Cross
Solution 3