低水準 I/O によるテキスト データ ファイルのインポート
概要
"低水準ファイル I/O 関数" では、ファイルの読み取りとファイルへのデータの書き込みを最大限に制御できます。ただし、importdata
などの使いやすい "高水準関数" に比べて、これらの関数ではファイルについて詳細な情報を指定する必要があります。テキスト ファイルの読み取りに使用する高水準関数の詳細は、テキスト ファイルのインポートを参照してください。
高水準関数でデータをインポートできない場合は、以下のいずれかを使用してください。
fscanf
は、テキスト ファイルや ASCII ファイル、つまりテキスト エディター表示が可能なファイルに含まれる書式設定済みデータを読み取ります。詳細は、書式設定済みパターン データの読み取りを参照してください。fgetl
およびfgets
ではファイルを 1 行ずつ読み取り、各行は改行文字によって区切られます。詳細は、行単位データの読み取りを参照してください。fread
ではデータ ストリームをバイトまたはビットの単位で読み取ります。詳細は、低水準 I/O によるバイナリ データのインポートを参照してください。
詳細は、以下の節を参照してください。
メモ
低水準ファイル I/O 関数は、ANSI® 標準 C ライブラリの関数を基に構成されています。ただし、MATLAB® にはそれらの関数の "ベクトル化" バージョンが含まれており、最小限の制御ループを使用して配列内のデータの読み取りと書き込みが行われます。
書式設定済みパターン データの読み取り
importdata
や textscan
では読み取れないテキスト ファイルをインポートするには、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 つのフィールド mtime
、mdate
および 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 つの関数 fgetl
と fgets
が用意されています。関数 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 のテスト
textscan
、fscanf
、または fread
を使用してデータを部分に分けて読み取る場合は、feof
を使用してファイル終端に達したかどうかを確認できます。
たとえば、ファイル mymeas.dat
が次の形態を取り、測定値セットの数に関する情報がない場合を仮定します。mtime
、mdate
、および 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);
ファイルを開く際にエンコードを指定すると、そのスキームは次の関数 fscanf
、fprintf
、fgetl
、fgets
、fread
および fwrite
で適用されます。
サポートされているエンコード スキームの一覧と、エンコードを指定する構文は、関数 fopen
のリファレンス ページを参照してください。