Main Content

低水準 I/O によるテキスト データ ファイルのインポート

概要

"低水準ファイル I/O 関数" では、ファイルの読み取りとファイルへのデータの書き込みを最大限に制御できます。ただし、importdata などの使いやすい "高水準関数" に比べて、これらの関数ではファイルについて詳細な情報を指定する必要があります。テキスト ファイルの読み取りに使用する高水準関数の詳細は、テキスト ファイルのインポートを参照してください。

高水準関数でデータをインポートできない場合は、以下のいずれかを使用してください。

詳細は、以下の節を参照してください。

メモ

低水準ファイル I/O 関数は、ANSI® 標準 C ライブラリの関数を基に構成されています。ただし、MATLAB® にはそれらの関数の "ベクトル化" バージョンが含まれており、最小限の制御ループを使用して配列内のデータの読み取りと書き込みが行われます。

書式設定済みパターン データの読み取り

importdatatextscan では読み取れないテキスト ファイルをインポートするには、fscanf の使用を検討してください。関数 fscanf ではファイルの形式を記述する必要がありますが、この形式の記述には多くのオプションがあります。

たとえば、下に示すようにテキスト ファイル mymeas.dat を作成します。mymeas.dat のデータには、一連の時刻、日付、および測定値が繰り返されています。ヘッダーのテキストには測定値のセットの数 N が含まれています。

Measurement Data
N=3

12:00:00
01-Jan-1977
4.21  6.55  6.78  6.55
9.15  0.35  7.57  NaN
7.92  8.49  7.43  7.06
9.59  9.33  3.92  0.31
09:10:02
23-Aug-1990
2.76  6.94  4.38  1.86
0.46  3.17  NaN   4.89
0.97  9.50  7.65  4.45
8.23  0.34  7.95  6.46
15:03:40
15-Apr-2003
7.09  6.55  9.59  7.51
7.54  1.62  3.40  2.55
NaN   1.19  5.85  5.05
6.79  4.98  2.23  6.99

ファイルを開く

あらゆる低水準 I/O 関数で行うように、読み取りの前に fopen でファイルを開き、ファイル識別子を取得します。既定では、'r' のアクセス許可で、fopen によってファイルが読み取りアクセス用に開きます。

ファイルの処理が終了したら、fclose(fid) を使用してこれを閉じます。

データの記述

テキストの '%s'、整数の '%d'、浮動小数点数の '%f' など、書式指定子によってファイルのデータを表現します (指定子の一覧は、fscanf のリファレンス ページを参照してください)。

ファイル内のリテラル文字をスキップするには、形式の記述にその文字を含めます。データ フィールドをスキップするには、指定子でアスタリスク ('*') を使用します。

たとえば、mymeas.dat のヘッダー行について考えます。

Measurement Data   % skip the first 2 words, go to next line:  %*s %*s\n
N=3                % ignore 'N=', read integer:  N=%d\n
                   % go to next line:  \n
12:00:00
01-Jan-1977
4.21  6.55  6.78  6.55
...

ヘッダーを読み取って N に 1 つの値を返すには、次のようにします。

N = fscanf(fid, '%*s %*s\nN=%d\n\n', 1);

読み取る値の数の指定

既定の設定により、fscanf では記述がデータに一致しなくなるまで、またはファイル終端に到達するまで、形式の記述が繰り返し適用されます。

オプションとして、読み取る値の数を指定して、fscanf によりファイル全体が読み取られないようにします。たとえば、mymeas.dat では測定値の各セットに一定数の行と列が含まれています。

measrows = 4;
meascols = 4;
meas  = fscanf(fid, '%f', [measrows, meascols])';

ワークスペースにおける変数の作成

MATLAB ワークスペースで mymeas.dat を保管する方法はいくつかあります。ここでは、値を構造体に読み取ります。構造体の各要素には次の 3 つのフィールド mtimemdate および meas があります。

メモ

fscanf では、列順で配列に数値が埋められます。出力配列がファイルの数値データの配置と一致するようにするには、配列を転置してください。

filename = 'mymeas.dat';
measrows = 4;
meascols = 4;

% open the file
fid = fopen(filename);

% read the file headers, find N (one value)
N = fscanf(fid, '%*s %*s\nN=%d\n\n', 1);

% read each set of measurements
for n = 1:N
    mystruct(n).mtime = fscanf(fid, '%s', 1);
    mystruct(n).mdate = fscanf(fid, '%s', 1);

    % fscanf fills the array in column order,
    % so transpose the results
    mystruct(n).meas  = ...
      fscanf(fid, '%f', [measrows, meascols])';
end

% close the file
fclose(fid);

行単位データの読み取り

MATLAB には、ファイルから行を読み取って文字ベクトルに格納する、2 つの関数 fgetlfgets が用意されています。関数 fgets では行と改行文字が出力にコピーされますが、fgetl ではコピーされません。

以下の例では、fgetl を使用してファイル全体を 1 行ずつ読み取ります。関数 litcount は、指定した文字シーケンス (literal) を各行で表示するかどうかを決定します。これを実行する場合、関数は、そのリテラルが行に含まれる数を示し、それに続けて行全体を表示します。

function y = litcount(filename, literal)
% Count the number of times a given literal appears in each line.

fid = fopen(filename);
y = 0;
tline = fgetl(fid);
while ischar(tline)
   matches = strfind(tline, literal);
   num = length(matches);
   if num > 0
      y = y + num;
      fprintf(1,'%d:%s\n',num,tline);
   end
   tline = fgetl(fid);
end
fclose(fid);

badpoem という名前の入力データ ファイルを作成します。

Oranges and lemons,
Pineapples and tea.
Orangutans and monkeys,
Dragonflys or fleas.

'an' がこのファイルにいくつ含まれるかを調べるには、litcount を呼び出します。

litcount('badpoem','an')

以下が返されます。

2: Oranges and lemons,
1: Pineapples and tea.
3: Orangutans and monkeys,
ans =
     6

ファイル終端 (EOF) のテスト

データを部分に分けて読み取る場合は、feof を使用してファイル終端に達したかどうかを確認できます。feof は、ファイル ポインターがファイル終端にあるとき 1 の値を返します。それ以外の場合は 0 を返します。

メモ

空のファイルを開いても、ファイルの位置指定子がファイル終端に "移動することはありません"。読み取り操作および関数 fseek と関数 frewind は、ファイル位置指定子を移動します。

feof による EOF のテスト

textscanfscanf、または fread を使用してデータを部分に分けて読み取る場合は、feof を使用してファイル終端に達したかどうかを確認できます。

たとえば、ファイル mymeas.dat が次の形態を取り、測定値セットの数に関する情報がない場合を仮定します。mtimemdate、および meas のフィールドをもつ構造体にデータを読み取ります。

12:00:00
01-Jan-1977
4.21  6.55  6.78  6.55
9.15  0.35  7.57  NaN
7.92  8.49  7.43  7.06
9.59  9.33  3.92  0.31
09:10:02
23-Aug-1990
2.76  6.94  4.38  1.86
0.46  3.17  NaN   4.89
0.97  9.50  7.65  4.45
8.23  0.34  7.95  6.46

ファイルを読み取るには次のようにします。

filename = 'mymeas.dat';
measrows = 4;
meascols = 4;

% open the file
fid = fopen(filename);

% make sure the file is not empty
finfo = dir(filename);
fsize = finfo.bytes;

if fsize > 0 

    % read the file
    block = 1;
    while ~feof(fid)
        mystruct(block).mtime = fscanf(fid, '%s', 1);
        mystruct(block).mdate = fscanf(fid, '%s', 1);

        % fscanf fills the array in column order,
        % so transpose the results
        mystruct(block).meas  = ...
          fscanf(fid, '%f', [measrows, meascols])';

        block = block + 1;
    end

end

% close the file
fclose(fid);

fgetl と fgets による EOF のテスト

制御ループで fgetl または fgets を使用する場合は、feof がファイル終端をテストする最良の方法であるとは限りません。代わりに、fgetl または fgets によって返される値が文字ベクトルであるかどうかを確認する方法を検討してください。

たとえば、行単位データの読み取りで説明した関数 litcount には、次の while ループと fgetl の呼び出しが含まれています。

y = 0;
tline = fgetl(fid);
while ischar(tline)
   matches = strfind(tline, literal);
   num = length(matches);
   if num > 0
      y = y + num;
      fprintf(1,'%d:%s\n',num,tline);
   end
   tline = fgetl(fid);
end

この方法は、以下の 2 つの理由で ~feof(fid) のテストよりもロバスト性が高くなります。

  • fgetl または fgets でデータが見つかった場合は、文字ベクトルが返されます。見つからない場合は数字 (-1) が返されます。

  • 読み取り操作が終わるごとに、fgetl および fgets ではファイル内の次の文字がファイル終端マーカーかどうかが確認されます。したがって、これらの関数では、-1 の値が "返される前に" ファイル終端指定子が設定される場合があります。たとえば、次に示す 3 行のテキスト ファイルについて考えます。最初の 2 行はどちらも改行文字で終了し、第 3 行にはファイル終端マーカーのみが含まれています。

    123
    456
    

    fgetl を 3 回続けて呼び出すと、次の結果が得られます。

    t1 = fgetl(fid);    % t1 = '123', feof(fid) = false
    t2 = fgetl(fid);    % t2 = '456', feof(fid) = true
    t3 = fgetl(fid);    % t3 = -1,    feof(fid) = true
    

    この動作は、関連する C 言語関数の ANSI 仕様には準拠していません。

異なった文字エンコードのファイルを開く

"エンコード スキーム" では、日本語や欧州の言語など、特定の文字体系で必要とされる文字がサポートされています。一般的なエンコード スキームには US-ASCII や UTF-8 などがあります。

読み取るファイルを開くときにエンコード スキームを指定しないと、fopen は自動文字セット検出を使用してエンコードを判定します。書き込むファイルを開くときにエンコード スキームを指定しないと、fopen は既定で UTF-8 を使用します。これは、データの損失または破損を起こすことなく、すべてのプラットフォームとロケール間での相互運用性を提供するためです。

既定の設定が何かを判断するには、ファイルを開き、次の構文で fopen を再度呼び出します。

[filename, permission, machineformat, encoding] = fopen(fid);

ファイルを開く際にエンコードを指定すると、そのスキームは次の関数 fscanffprintffgetlfgetsfread および fwrite で適用されます。

サポートされているエンコード スキームの一覧と、エンコードを指定する構文は、関数 fopen のリファレンス ページを参照してください。