Swiftでファイルに入出力する場合には、FileHandle を使う。内部的にはファイル記述子(file descriptor)を使っていてそちらのほうが細かな制御はできるのだろうが、Data、StringといったSwiftのオブジェクト型を使っている場合にはそのまま扱えるFileHandleのほうが便利だ。

今回 forWriting: として書き込み用途で FileHandle を作ろうとしたがなぜかファイルに書き込みできていなくて色々調べることになった。

普段からFileHandleを使っていたはずだが、forReading: 読み込みばかりで使っていたようだ。よく考えれば、StringやData、さらにはUIImage等にはpathまたはurlを指定して直接入出力するメソッドがありあまりFilehandleを直接操作する必要がなかった。


調べて見ると、FileHandle.init?(forWritingAtPath path: String)、init(forWritingToURL url: NSURL) throws は、指定したファイルが存在しない場合には失敗するという。 fopen() 等でも書き込み目的でファイルを開くときにファイルがなければ作成するか、失敗するか指定するオプションがあったがそれに相当しているようだ。が、ファイル作成を指示するオプション引数などはこのメソッドにはない。

別途、FileManager.init(forWritingToURL url: NSURL) throws 等を使ってファイルを事前に作成しておく必要がある。

Swift2(path)
let path = ...
NSFileManager.defaultManager().createFileAtPath(path, contents: nil, attributes: nil)
let handle = NSFileHandle(forWritingAtPath: path)



Swift3(url)
do {
    FileManager.default.createFile(atPath: file, contents: nil, 
   attributes: [FileAttributeKey.extensionHidden: true])
    let fileURL = URL(fileURLWithPath: file)
    let fileHandle = try FileHandle(forWritingTo: fileURL)
} catch let error {
    print(error)
}