sironekotoroの日記

Perl で楽をしたい

Perlでテキストファイルの中身を表示する

色々書いたけど省略

  1. CSVファイルを処理する方法について書いておきたい
  2. そもそも、ファイルの入出力についてPerl入学式の現行カリキュラムでやってない
  3. しかもいい感じのCSVファイルのサンプル、Shift-JISフォーマットじゃん
  4. ・・・一歩ずつ、ファイル入出力からやっていこう

Perlでテキストファイルの中身を表示する

では早速ファイルを用意します・・・と思って適当なの探したんだけど、良い感じのデータがない・・・ので、プログラムファイル自身を表示する、というふうに方向転換します。

read_file.pl という名前のスクリプトを作り、実行してみます。

Perlでファイルを読み込む(手作業編)

#!/usr/bin/env perl
use strict;
use warnings;

my $filename = 'read_file.pl';    # ファイル名を指定する

open my $FH, '<', $filename;       # ファイルハンドルを宣言する

for my $line (<$FH>) {  # 行入力演算子で1行ずつ読み込む
    chomp $line;
    print $line . "\n";
}

close $FH;    # ファイルを閉じる

実行すると、スクリプト自身を表示します。

Perl入学式の現行カリキュラムではファイルの取り込みや書き込みは学習しませんので、ここで少し解説です。

Perlではファイルハンドルというものを使ってファイルの読み書きを行います。

ファイルハンドルは「ファイルを扱うもの」くらいに思っておいてください。直訳じゃん・・・

コードの中では $FH という変数がファイルハンドルです。

open という関数を使ってファイルハンドルを宣言してファイルを open し、使い終わったらファイルハンドルを close します。

open my $FH, '<', $filename;    # ファイルハンドルにファイルを読み込ませる

# 何らかの処理を書く

close $FH;                          # ファイルハンドルを終了する

これだけだと、ファイルハンドルを設定して終了しただけです。

この、 openclose の間に処理を書きます。今回書かれているのは・・・

for my $line (<$FH>){
    chomp $line;
    print $line . "\n";
}

おなじみのfor文です。 <$FH> 以外のところはPerl入学式の第2回でやったところです。こんな感じですね。

for my $line ( 0..9 ){
    chomp $line;
    print $line . "\n"; # 0 から 9 までを改行して表示する
}

では、この <$FH> はどういう意味でしょう・・・となる前にもう一つ、Perl入学式でやった標準入力を思い出してみます。

#!/usr/bin/env perl
use strict;
use warnings;

my $line = <STDIN>;
chomp $line;
print $line . "\n";

似ていますね、 <$FH><STDIN>

この <> は行入力演算子というもので、その名の通り、行単位で1行ずつ読み込んでくれるものです。

<STDIN> の場合には標準入力を enter キーが押されるごとに、<$FH>の場合にはファイルを1行ずつ読み込んでいます。

perldoc.jp

こんな感じで、

  1. oepn でファイルハンドルを宣言し、ファイルを開く

  2. 開いたファイルから1行読み取り、何か処理をする(今回は表示する)

  3. close でファイルハンドルを閉じる

という一連の処理がファイルの処理の基本となります。

Perlでファイルを書き込む(手作業編)

こちらでもファイルハンドルを使っていきます。

今回はFizzBuzzをファイルに出力してみます。

#!/usr/bin/env perl
use strict;
use warnings;

my $filename = 'fizzbuzz.txt';
open my $FH, '>', $filename; # ファイルを書き込むときは不等号の向きが ファイル名側になる

for my $n ( 1 .. 100 ) {
    if ( $n % 3 == 0 && $n % 5 == 0 ) {
        print $FH "FizzBuzz" . "\n";    # 一見普通のprint文・・・?
    }
    elsif ( $n % 3 == 0 ) {
        print $FH "Fizz" . "\n";
    }
    elsif ( $n % 5 == 0 ) {
        print $FH "Buzz" . "\n";
    }
    else {
        print $FH $n . "\n";
    }
}

close $FH;

実行しても特に表示は出ませんが、fizzbuzz.txt というファイルがスクリプトと同じ場所に作成されています。

では解説です。

fizzbuzzの処理を open, close で囲っています。ここはファイルを読み込んだ時と同じです。

ただし、open したときの不等号の向きに注意してください。

open my $FH, '>', $filename; # ファイルを書き込むときは不等号の向きが ファイル名側になる

不等号がファイル名側を指しているのがファイルへの書き込みです。

そしてもう一つ。

print $FH "FizzBuzz" . "\n"; # 一見普通のprint文・・・?

print のところにファイルハンドル $FH が入っています。

これにより、各数字のfizzbuzzの結果がファイルハンドル経由でファイルに書き込まれています。

カンマは無しで、print と表示したい文字列や変数の間にスペース区切りでファイルハンドルを記述します。

ファイルの読み込みと書き込みを同じスクリプトで行う

ファイルハンドルを2つ用います。

今回は先に作成した fizzbuzz.txt を読み込んで、逆順のファイルを作成する、というスクリプトを書いてみました。

#!/usr/bin/env perl
use strict;
use warnings;

my $read_filename = 'fizzbuzz.txt';
my $write_filename = 'reverse_fizzbuzz.txt';

my @array = ();

# ファイルの読み込み
open my $READ, '<', $read_filename;
for my $line (<$READ>) {
    chomp $line;
    push @array, $line;
}
close $READ;


# ファイルの書き込み
open my $WRITE, '>', $write_filename;
for my $line (reverse @array){
    print $WRITE $line . "\n";
}
close $WRITE;

ファイルに追記したい(手作業編)

ファイハンドルを宣言するときの不等号を >> とします。直感的!

ファイル入出力をモジュールで

IO::Fileがメジャーだと思います。Perlの組み込みモジュールであり、use IO::File するだけで利用できます。

fizzbuzz.txt を読み込むスクリプトです。

#!/usr/bin/env perl
use strict;
use warnings;

use IO::File;

my $FH = IO::File->new('fizzbuzz.txt', '<');
for my $line ( <$FH> ){
    print $line;
}
$FH->close();