Posted at

Rで一時ファイルの利用

More than 1 year has passed since last update.

ちょいちょい忘れては調べることになるのでメモ。


一時ファイル

一時ファイルとは一時的なデータを保持しておくファイルで、通常さくっと作られて用が済めば削除されるものです。Rでも自分で準備して利用することが可能で、ちょっとデータなどを預けておいたりするのに重宝します。今回はこれの基本的なところを確認。


tempfile関数とtempdir関数

Rの場合、作成した一時ファイルは一時ディレクトリに置かれます。そしてこの一時ディレクトリはそのRsessinoで準備されています。その一時ディレクトリへのパスを取得する関数がtempdir()です:

tempdir()

#> [1] "/tmp/RtmpLapPwK"

ルートからのパスはOSや環境に依存しますが、一時ディレクトリ名はRtmp*という名前になるようです。

では今度は一時ファイルを作成してみたいと思います。一時ファイルを作成する関数はtempfile()関数です:

tempfile()

#> [1] "/tmp/RtmpLapPwK/file9403432469"

上のtempdir()で出てきたディレクトリにfile*というファイルが作成されて、そのファイルへのパスが返ってきます。通常はこのようにするのではなく、返り値をオブジェクトに預けます:

tmpf <- tempfile()

tmpf
#> [1] "/tmp/RtmpLapPwK/file940709780f0"
class(tmpf)
#> [1] "character"

このように預けておくと、このパスを利用してファイル操作ができるようになります:

kosaki <- c("kosaki", "yappari", "saikou!")

writeLines(kosaki, tmpf)
readLines(tmpf)
#> [1] "kosaki" "yappari" "saikou!"


Usage

tempdir()関数には引数はありません。単に一時ディレクトリのパスを返すのみです。tempfile()のUsageは以下のとおりです:

tempfile(pattern = "file", tmpdir = tempdir(), fileext = "")


  • pattern


    • 空ではない文字列ベクトルを指定

    • 一時ファイル名の最初の部分がこれになります

    • 初期値は"file"なので、上述のようにfile*という名に



  • tmpdir


    • 空ではない文字列ベクトルを指定

    • 一時ファイルを設置するディレクトリ名を指定

    • 初期値はtempdir()であり、上述した一時ディレクトリに格納される



  • fileexit


    • 空ではない文字列ベクトルを指定

    • 一時ファイルの拡張子を設定

    • 初期値は空の文字列で、つまりは拡張子なしのファイル



ということで、内容はシンプルです。ポイントは以下のようなところ:


  • 文字列ベクトルを受け付ける、すなわち一度にたくさん作れる

  • 一時ファイル名でもpatternである程度は付与できる

  • .csv.txt、あるいは.html.mdなどいろいろできる


いろいろ試してみる

てことで遊んでみます。まずは複数作成。

tempfs <- tempfile(paste("kosaki", 1:3, sep = "_"))

tempfs
#> [1] "/tmp/RtmpLapPwK/kosaki_194012d6e993"
#> [2] "/tmp/RtmpLapPwK/kosaki_2940a2bce14"
#> [3] "/tmp/RtmpLapPwK/kosaki_394076b5137c"

文字列ベクトルで与えると、それに合わせて準備してくれました。

次はいろんな拡張子を与えてみます:

tempfs <- tempfile("kosaki", fileext = c("", ".txt", ".csv", ".html"))

tempfs
#> [1] "/tmp/RtmpLapPwK/kosaki9407c1cc7d4"
#> [2] "/tmp/RtmpLapPwK/kosaki9401f98b725.txt"
#> [3] "/tmp/RtmpLapPwK/kosaki9403cda92a8.csv"
#> [4] "/tmp/RtmpLapPwK/kosaki940179b1fe6.html"

こんな感じですね。実用性はほぼ無いですがテストしました。

では、ちょっと長いですが応用です:

# 前準備: 独自でRコードをマークアップした文字列を準備

hoge <- paste(
"最初",
"<s>",
"paste('kosaki', 'No.1')",
"<e>",
"終わり",
"",
sep = "\n"
)

# 手順1: ターゲットを一時ファイルへ格納
tmp <- tempfile(fileext = c(".txt", ".R"))
write(hoge, tmp[1])

# 手順2: 一時ファイルから文字列ベクトルとして読みだす
xx <- readLines(tmp[1])

# 手順3: 読みだした文字列ベクトルからRコードの位置を特定して一時ファイル(.R)へ
chunk_start <- grep("<s>", xx)
chunk_end <- grep("<e>", xx)
r_chunk <- xx[chunk_start:chunk_end]
r_code <- r_chunk[!grepl("<s>|<e>", r_chunk)]
write(r_code, file = tmp[2])

# 手順4: 一時ファイルのコードを評価
out <- eval(parse(tmp[2]))

# 手順5: 出力を元のテキストに埋め込む

finish <- c(
xx[1:chunk_end],
"<out_s>",
print(out),
"<out_e>",
xx[(chunk_end + 1):length(xx)]
)

# 手順6: ファイルとして出力
write(paste(finish, collapse = "\n"), file = "output.txt")
file.copy(paste(tmp[2], collapse = "\n"), "r_code.R")

伝わる人には伝わると思いますが、これはknitをイメージした処理です。実際の処理はもっと細やかにやるものなのですが、あくまで一時ファイルを使った例なのでざっくりやりました。

この一時ファイルはいろんなところで使われていて、パッケージの関数内処理で作成しているとかよく見かけます。ぜひ活用してみてください。

Enjoy!