概要

Juliaのファイル操作系の機能を使ってみる。

cd, pwd, mv, cp, touchといった馴染みの名前が関数名になっているので、非常に覚えやすい。

バージョンは0.3.4を使用。ソースコードを見るとまだ定まってない感が醸しだされているので、バージョンが変わるといろいろ変更は出そう。

機能の一覧は下記参照
http://julia.readthedocs.org/en/latest/stdlib/file/

@CretedDate 2015/01/08
@Versions Julia0.3.4

ファイルの書き込み

writeで書き込める。戻り値は書き込んだバイト数。

# openしてブロック内で書き込み
open( "a.txt", "w" ) do fp
  write( fp, "日本語を書き込んでみる\n" )
end

# 追記
open( "a.txt", "a" ) do fp
  write( fp, "追記してみる\n" )
  println( fp, "printlnしても良い" )
end

上記のようにブロック内で書いた場合、closeは自動で行われる。具体的には下記のような処理が呼ばれている。

function open(f::Function, args...)
  io = open(args...)
  try
    f(io)
  finally
    close(io)
  end
end

ブロックを使わずに下記のように書くこともできる。

fp = open("ファイル名")
write( fp, "書き込み" )
close( fp )

このへんはRubyの書き方に近いイメージ。

尚、STDOUTを指定してwriteすると、標準出力に出力される。

write( STDOUT, "標準出力に出力する" )
  #=> 標準出力に出力する27

ファイルの読み込み

eachlineで1行ずつ読み込んでみる。

open( "a.txt", "r" ) do fp
  for line in eachline( fp )
    print( line )
  end
end

readallで全文字を読み込む。

str = open( "a.txt", "r" ) do fp
  readall( fp )
end

各行を配列として読み込む。

lines = open( "a.txt", "r" ) do fp
  readlines( fp )
end

ちなみに0.3.4時点だとJuliaのreadlineは readline(s::IO) = readuntil(s, '\n') とされていて、うちの環境では\rは改行として認識されない。改行コードの扱いはOSごとで変わるんかな。(未調査)

文字コードは基本、UTF-8。sjisとかeucのファイルを読みたい時は……どうするんだろう。ざっとdocument見たけどそれっぽいものは見当たらなかった。iconv噛ませてどうこうとかするんかな。

openの引数に関数を渡すこともできる。

# 処理を関数で書いておいて、openに渡す場合
f( fp ) = for line in eachline( fp )
  print(line)
end

open( f, "a.txt" )

この場合も自動でcloseは行われる。

gzipファイルの読み書き

GZipパッケージを利用。

読み込み

# 準備
Pkg.add("GZip")
import GZip

# ブロックで処理を渡す
GZip.open( "foo.gz" ) do fp
  for line in eachline( fp )
    print( line )
  end
end

# 関数で処理を渡す
f( fp ) = for line in eachline( fp )
  print(line)
end
open( f, "foo.gz" )

書き込み

GZip.open( "tmp.gz", "w" ) do fp
  write( fp, "1行目\n" )
  write( fp, "2行目\n" )
end

ファイルのコピー

cp(コピー元, コピー先) でコピー可能。戻り値はFile型。

# コピー用のファイルを作成しておく
touch("a.txt")

# コピー
_file = cp( "a.txt", "b.txt" )
#=> > File("b.txt",false,-1)

File型は、help( "File" ) で見てみると、open, cp, mvなどひと通りのことは出来る様子。

ファイルの移動

mv(移動元, 移動先) で移動可能。戻り値はNothing。

mv( "a.txt", "c.txt" )

ファイルの削除

rmで削除

# ファイルの削除
rm("a.txt")

# ディレクトリも消せるけど空じゃないとエラーになる
rm("dir1")
  #=> ERROR: rmdir: ディレクトリは空ではありません

# recursiveをtrueに設定すれば空じゃなくても消せる
rm("dir1", recursive=true)

ディレクトリの作成

mkdirで作れる。

mkdir( "foo" )

# 既に存在する場合は例外
mkdir( "foo" )
  #=> ERROR: mkdir: ファイルが存在します

# mkdirは再帰的には掘れない
mkdir( "foo/bar/baz" )
  #=> ERROR: mkdir: そのようなファイルやディレクトリはありません

# 2階層以上掘りたい場合はmkpathを使う。
mkpath( "foo/bar/baz" )

ディレクトリ配下のファイル一覧を取得する

カレントディレクトリの下を一覧で出す。readdirを使う。

readdir( "." )

# filterとisfileでファイルだけを抽出する
filter(f -> isfile(f), readdir("."))

# isdirでディレクトリだけを抽出する
filter(f -> isdir(f), readdir("."))

ディレクトリを再帰的に見る(0.3.4の段階では末尾再帰の最適化はないらしい)

f(dir) = for child = readdir(dir)
  child = joinpath(dir, child)
  println( abspath( child ) )
  isdir( child ) && f( child )
end

f(".")

ファイル情報の取得

ファイルサイズはfilesizeで取れる。

filesize( "a.txt" )

作成日や更新日はctime, mtimeで取れる。

ctime( "a.txt" )
  #=> 1.420523529135508e9

mtime( "a.txt" )
  #=> 1.4205235290955074e9

floatで返ってくる。int( ctime( "a.txt" ) ) するとunix timestampになる。

URLを指定してダウンロード

download( "http://www.yahoo.co.jp/", "foo.txt" )

ちなみにこれ、UNIX系のOSだと下記のようにwgetとかcurlとかが入ってたら叩くというだけの処理をしてる。

if downloadcmd == :wget
  run(`wget -O $filename $url`)
elseif downloadcmd == :curl
  run(`curl -o $filename -L $url`)
elseif downloadcmd == :fetch
  run(`fetch -f $filename $url`)
else
  error("no download agent available; install curl, wget, or fetch")
end

Windows系だと別途何かを叩いてるっぽい。