RNULL文字(0x00)を含むテキストファイルを作る(翌日の記事)
Contents


実行環境



ファイルの例

作業としては、先日、更新時刻順でファイルリストを作った続きです。「数値がスペース区切りで入ってる」と聞いていたファイルを、とりあえずMery(エディタ)で開いたら「ファイルに含まれていたNULL文字は、スペースに変換して開きます」とのメッセージ。


実際の中身は載せられないので簡単なダミーで示すと ↓ こんな感じ。二つ目の画像はStirling(バイナリエディタ)で開いたところ。改行(LF、0x0A)の後、確かに0x00があります。ダミーファイルの実物は
こちら。

追記(9月20日)上の画像は最初にDOSで作成したもので、ファイル終端に余分な制御文字(EOF、0x1A)が入っており、その後作り直しました。メモ帳で開いた時に全然読めない ↓ のも、このためです。詳しくは翌日の記事を参照。


Rで、NULL文字をスキップして1行ずつベクトルに入れる

ファイル読み込みの関数・方法はいろいろですが、今回は(1)readLinesNULL文字をスキップして1行ずつペクトルに入れる(2)各行を空白で分割して列に変換、という手順でmatrixにしました。(2)でstrsplit関数の結果を数値に変換してmatrixにする所が少し面倒。もっと簡単な方法があるかもしれません。sapply関数でつなげると何故か列方向になったので、とりあえず転置しました。
rows = readLines('R:/TMP/all.prn', skipNul=T)
print(rows)

[1] "1 1 1 1 1 1 1 1 1 1"
[2] "2 2 2 2 2 2 2 2 2 2"
[3] "3 3 3 3 3 3 3 3 3 3"
[4] "4 4 4 4 4 4 4 4 4 4"
[5] "5 5 5 5 5 5 5 5 5 5"
[6] "6 6 6 6 6 6 6 6 6 6"
[7] "7 7 7 7 7 7 7 7 7 7"
[8] "8 8 8 8 8 8 8 8 8 8"
[9] "9 9 9 9 9 9 9 9 9 9"
mat = t(sapply(strsplit(rows, ' '), as.numeric))
print(mat)

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    1    1    1    1    1    1    1    1    1     1
 [2,]    2    2    2    2    2    2    2    2    2     2
 [3,]    3    3    3    3    3    3    3    3    3     3
 [4,]    4    4    4    4    4    4    4    4    4     4
 [5,]    5    5    5    5    5    5    5    5    5     5
 [6,]    6    6    6    6    6    6    6    6    6     6
 [7,]    7    7    7    7    7    7    7    7    7     7
 [8,]    8    8    8    8    8    8    8    8    8     8
 [9,]    9    9    9    9    9    9    9    9    9     9

以下は(2)での少し違う書き方。sapplyでなくlapply関数を使うと ↓ こんな感じ。いずれにしてもstrsplitlistを返すので、自分の知ってる範囲だと妙にややこしい手順しかできません。
do.call(rbind, lapply(strsplit(rows, ' '), as.numeric))

まず文字型のままmatrixにし、後から数値に直す方が ↓2行になるけど分かりやすいかも。
mat = do.call(rbind, strsplit(rows, ' '))
apply(mat, 2, as.numeric)

普通のプログラミング言語のようにFORループなら ↓ こんな感じ。数値以外のデータがあるとas.numericが失敗して止まるので、問題箇所の把握には有利。
lis = strsplit(rows, ' ')
mat = NULL
for (i in 1:length(lis)) {
    mat = rbind(mat, as.numeric(lis[[i]]))
}
print(mat)


ファイル読み込みで失敗した例

NULL文字を考慮せず普段のようにやってみて失敗した例を、後々のため載せておきます。まずreadLines関数でオプションskipNul=TRUEがないと ↓ こんな風に2行目以降が取得できません。
readLines('R:/TMP/all.prn')

 [1] "1 1 1 1 1 1 1 1 1 1" ""                    ""
 [4] ""                    ""                    ""
 [7] ""                    ""                    ""
[10] ""
Warning messages:
1: In readLines("R:/TMP/all.prn") :
  line 2 appears to contain an embedded nul
2: In readLines("R:/TMP/all.prn") :
  line 3 appears to contain an embedded nul
3: In readLines("R:/TMP/all.prn") :
  line 4 appears to contain an embedded nul
4: In readLines("R:/TMP/all.prn") :
  line 5 appears to contain an embedded nul
5: In readLines("R:/TMP/all.prn") :
  line 6 appears to contain an embedded nul
6: In readLines("R:/TMP/all.prn") :
  line 7 appears to contain an embedded nul
7: In readLines("R:/TMP/all.prn") :
  line 8 appears to contain an embedded nul
8: In readLines("R:/TMP/all.prn") :
  line 9 appears to contain an embedded nul
9: In readLines("R:/TMP/all.prn") :
  line 10 appears to contain an embedded nul
10: In readLines("R:/TMP/all.prn") :
  incomplete final line found on 'R:/TMP/all.prn'

read.table関数でデリミタを半角スペースに指定したら、なぜか25行目が飛ばされました。
read.table('R:/TMP/all.prn', sep=' ')

  V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1  1  1  1  1  1  1  1  1  1   1
2 NA  6  6  6  6  6  6  6  6   6
3 NA  7  7  7  7  7  7  7  7   7
4 NA  8  8  8  8  8  8  8  8   8
5 NA  9  9  9  9  9  9  9  9   9
Warning messages:
1: In read.table("R:/TMP/all.prn", sep = " ") :

  line 2 appears to contain embedded nulls
2: In read.table("R:/TMP/all.prn", sep = " ") :

  line 3 appears to contain embedded nulls
3: In read.table("R:/TMP/all.prn", sep = " ") :

  line 4 appears to contain embedded nulls
4: In read.table("R:/TMP/all.prn", sep = " ") :

  line 5 appears to contain embedded nulls
5: In scan(file = file, what = what, sep = sep, quote = quote, dec = dec,  :
  embedded nul(s) found in input


もしファイルにNULL文字がなければ、上の二つとも ↓ 正常に読めます。

ところで、今日の記事用に
NULL文字入りファイルRで作るのが少し面倒でした。ファイルの最後だけに入れるなら簡単な一方、各行末に入れるというのが意外にできず、結局DOScopyコマンドを使用。何の役にも立ちませんが、せっかくなので明日書きます。
追記(9月20日)その後、Rだけでできました。詳細は翌日の記事を参照。