I'm not about to write my own version here, just offer some pointers I find makes life easier for myself, and they may help others too if you're not bound to "I don't want to use CPAN".
These days, I find it easier and safer to just use > use Path::Tiny qw(path); > > my $infile = path('numbers.txt')->openr; > my $outfile = path('sumfile.txt')->openw; Those will open files and do the right things with error handling by default. If you decide you want a unfiltered IO stream ( ie: not subject to the CRLF filter on win32 ), its easy to simply switch to openr_raw and openw_raw, and it will do the right thing. Likewise, if you decide you want utf8, just openr_utf8 and openw_utf8 ( there's a lot of complex messy bugs in utf8 io that this avoids ) Similarly, instead of: > chomp( my @lines = <$infile> ); You can simply do: > my (@lines) = path('numbers.txt')->lines({ chomp => 1 }); ( And again, you can just bolt on the _raw and _utf8 suffixes and get the right result ) If you want to avoid handling close yourself and you have a mass of data you just want to write and have errors handled correctly: > path('sumfile.txt')->spew(map { "$_\n"} @lines ); And again, you can just bolt on _utf8 and _raw suffixes and get the right thing. Spew also adds extra protection by writing to a temporary file , and then moving it over the original one, so that if spew for some reason fails half way through, the original file should not be affected. -- Kent *KENTNL* - https://metacpan.org/author/KENTNL