プログラム学習室 http://studyhallweb.com/

Dart言語: ファイルの読み込み(行単位)

readAsLines()

下のコードを実行したとき、ファイルを読み込んでいるループより、その後の処理が前に実行されているような結果になる。
これはDartの非同期処理によるものらしい。
Webではダウンロードなど時間がかかわる処理があるので、それはそれで行わせておいて、別の処理を進めやすいようにしていると思われる。
import 'dart:io';

void main() {
int n, i, j;
List<String> sReadFile = new List();

new File('ReadTest.txt').readAsLines().then((List<String> slines) {
n = slines.length;
print('行数$n');
for (i = 0; i < n ; i++){
  print(slines[i]);
}
sReadFile = slines;
for (j = 0; j < n ; j++){
  String s = sReadFile[j];
  print('File Read のループ内 :$s');
}
});

// ここから下のほうが先に実行される
n = sReadFile.length;
print('なぜか先に?? n=$n');
for (i = 0; i < n ; i++){
print('n=0 のため、ここは実行されない');
print(sReadFile[i]);
}

}
      

このソースの実行結果
読み込むファイルの中身は「1行目\r\n2行目\r\n3行目\r\n」と書いてある。(\r\nは改行コード)
なぜか先に?? n=0
行数3
1行目
2行目
3行目
File Read のループ内 :1行目
File Read のループ内 :2行目
File Read のループ内 :3行目
			

readAsLinesSync()

readAsLines() の同期処理版である readAsLinesSync() を使ったほうが、シンプルで分かりやすくなる。
非同期で処理する必要がなければ、こちらの方がよさそう。
import 'dart:io';

void main() {
  List<String> sReadFile = new List();

  File oFile = new File('ReadTest.txt');
  sReadFile = oFile.readAsLinesSync();  // この1行で読み込みは終了

  sReadFile.forEach((String s) {
    print(s);
  });
}
			



Dart言語: ファイルのエンコード

encoding.dart

文字コードは UTF-8 がデフォルトであり、Shift-JIS のファイルを読み込ませようとするとエラーが発生する。
上の readAsLinesSync() でも読み込み時の文字コードを readAsLinesSync(encoding: UTF8) のようにして指定できるが、Shift-JISには対応していないらしい。
Dartがインストールされているディレクトリ内の \dart-sdk\lib\convert\encoding.dart は次のようになっている。(2014-03-21現在)
これから encoding: で指定できるのは LATIN1, ASCII, UTF8 だけらしい。
  // All aliases (in lowercase) of supported encoding from
  // http://www.iana.org/assignments/character-sets/character-sets.xml.
  static Map<String, Encoding> _nameToEncoding = <String, Encoding> {
    // ISO_8859-1:1987.
    "iso_8859-1:1987": LATIN1,
    "iso-ir-100": LATIN1,
    "iso_8859-1": LATIN1,
    "iso-8859-1": LATIN1,
    "latin1": LATIN1,
    "l1": LATIN1,
    "ibm819": LATIN1,
    "cp819": LATIN1,
    "csisolatin1": LATIN1,

    // US-ASCII.
    "iso-ir-6": ASCII,
    "ansi_x3.4-1968": ASCII,
    "ansi_x3.4-1986": ASCII,
    "iso_646.irv:1991": ASCII,
    "iso646-us": ASCII,
    "us-ascii": ASCII,
    "us": ASCII,
    "ibm367": ASCII,
    "cp367": ASCII,
    "csascii": ASCII,
    "ascii": ASCII,  // This is not in the IANA official names.

    // UTF-8.
    "csutf8": UTF8,
    "utf-8": UTF8
  };
				

encoding: LATIN1

Shift-JIS のファイルを readAsLinesSync() で読み込むと次のエラーが発生する。
FileSystemException: Failed to decode data using encoding 'utf-8', path = '(読み込んだファイル名)'
下記のコードで試してみたところ encoding: LATIN1 を指定すればエラーは発生せずに読み込むことが出来る。
ただし、読み込んだ String を表示すると全角文字は文字化けする。
ちなみに encoding: を指定するには dart:convert の import が必要。
import 'dart:io';
import 'dart:convert';

void main() {
  List<String> sReadFile = new List();

  File oFile = new File('ReadTest_SJIS.txt');
                        // このファイルは Shift-JIS
  try {
    sReadFile = oFile.readAsLinesSync();  // ここでエラー発生
  } on Exception catch(e) {
    print(e.toString());
    String sErr = "FileSystemException: Failed to decode data using encoding 'utf-8'";
    if (e.toString().indexOf(sErr) == 0) {
      sReadFile = oFile.readAsLinesSync(encoding: LATIN1);
                          // これならば Shift-JIS もエラーにならない
    }
  }
  sReadFile.forEach((String s) {
    print(s);    // ただし、ここで文字化け
  });
}