Objective-C ファイル書き込み writeToFile 【初級編 第23回】

この記事は2013年2月26日に書かれたものです。内容が古い可能性がありますのでご注意ください。


writeToFile ファイルの書き込み

ファイルにデータの保存

前回の<Objective-C ファイル読み込み 【初級編 第22回】>ではNSStringを使用したファイルの読み込みを行いました。
ファイルから読み込んだデータを使用して処理を行うといったコードでした。
読み込んだデータを使用して何かの処理を行った後、その結果を保存しておきたいとなった場合、DBに保存するなどの方法が
考えられますが今回はファイルに書き込む方法を紹介したいと思います。

ファイルに書き込み

ファイルの書き込みにも今回はNSStringクラスを使用します。いろいろ使えるクラスですね。
NSStringクラスに「writeToFile」というメソッドが用意されていて、このメソッドはNSStringオブジェクトの内容を
ファイルに書き込みます。
私の環境のGNUStepのNSString.hでは以下のように定義されていました。

- (BOOL) writeToFile: (NSString*)path
         atomically: (BOOL)atomically
         encoding: (NSStringEncoding)enc
         error: (NSError**)error;

1つ目の引数はファイルへのパスを表す文字列オブジェクトを指定します。

2つ目の引数はファイルに書き込む際に一時ファイルを作成して保存してから、リネームするやり方をするかどうかを
指定します。そうすることで不完全なファイルにならないようです。
「YES」をするとそのやり方でファイルを作成します。NSString.mには以下のように書いてあります。
if set will cause the contents to be written to a temp file,
which is then closed and renamed to filename. Thus, an incomplete file at filename should never result.

3つ目の引数はファイルに書き込む際の文字コードを指定します。前回も登場したNSStringEncoding列挙型の定数を
指定します。

4つ目の引数はNSErrorオブジェクトを指定します。エラーの情報を管理するために使用されるクラスとなります。
前回も出てきましたが「*」が2つついているのでポインタのポインタということになります。

戻り値は問題なければ「YES(1)」とかえってくるようです。

コードでの確認

今回は「Manage.m」の方で最適BMI値に近い人をファイルに書き込むことにします。

Manage.h

#import <Foundation/NSObject.h>
#import "Person.h"

@interface Manage:NSObject
{
    Person *person;
}
-(Person*)person;
-(void)setPerson:(Person*)p;
-(void)showBestPerson;
-(void)recordBestPerson;
@end

11行目が追加されたところです。書き込み用のメソッド「recordBestPerson」を定義しているだけです。

manage.m

#import <Foundation/Foundation.h>
#import <math.h>
#import "Manage.h"
#import "Bmi.h"

@implementation Manage
-(Person*)person{
    return person;
}
-(void)setPerson:(Person*)newPerson{
    double num;
    if(person!=nil){
        num = fabs(22 - [Bmi calcBmi:[person weight] height:[person height]]) -
            fabs(22 - [Bmi calcBmi:[newPerson weight] height:[newPerson height]]);
        if( num > 0){
            [person release];
            person=newPerson;
            [person retain];
        }
    }else{
        person=newPerson;
        [person retain];
        }
    }else{
        person=newPerson;
        [person retain];
    }
}
-(void)showBestPerson
{
    printf("Best Person is %sn",[[person name] UTF8String]);
    printf("weight:%2.1fn",[person weight]);
    printf("height:%2.2fn",[person height]);
    printf("Bmi:%2.1fn",[Bmi calcBmi:[person weight] height:[person height]]);
}
-(void)recordBestPerson
{
    NSError *error = nil;
    NSString *writeString =
        [[NSString alloc] initWithFormat:@"Name:%@ Weight:%2.1f Height:%2.1f Bmi:%2.1fn",
        [person name],
        [person weight],
        [person height],
        [Bmi calcBmi:[person weight] height:[person height]]];
    [writeString writeToFile:@"record.txt"
                 atomically:YES
                 encoding:NSUTF8StringEncoding
                 error:&error];
    [writeString release];

}
-(void)dealloc{
    [person release];
    [super dealloc];
}
@end

39から44行目のところは長くなってしまったため行を変えていますが、1つのメッセージ式に複数の引数を指定しているだけです。
ここでは変数を埋め込んだ文字列を作成するために「initWithFormat」メソッドを使用しています。
このメソッドは以下のように「NSString.h」で以下のように定義されていました。

- (id) initWithFormat: (NSString*)format, ...;

このメソッドの引数はObjective-C 文字列操作,結合,切り出し 【初級編 第18回】で使用した
「stringByAppendingFormat」と同様です。引数「format」のところに書式を指定した文字列をいれ、
その文字列に埋め込みたい変数を複数後ろに指定するというものになります。
今回は名前、体重、身長、BMI値をそれぞれ埋め込んだ文字列を作成するために使用しています。
「@”Name:%@ Weight:%2.1f Height:%2.1f Bmi:%2.1f”」で「%@」が文字列を表し[persen name]の値がそこに入ります。
3つの「%f」が小数を表し、 [person weight],[person height],[Bmi calcBmi:[person weight] height:[person height]]が
順番に入ります。2.1は桁数を表しています。小数点より前に2ケタ後ろが1ケタということになります。

45行目から48行目はファイルに書き込みする処理となっています。
先ほど作成したNSStringオブジェクトに対して「writeToFile」メッセージを送信します。
書き込むファイル名は「record.txt」としています。
一時ファイルを作成して保存してから、リネームするやり方を使用するため第2引数では「YES」を指定しています。
文字コードはLinuxなのでUTF8にしています。

49行目では作成したNSStringオブジェクトを解放しています。「init」がついたメソッドを使用して作成したものは解放する
必要があるため入れておかなければなりません。

main.m

#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>
#import "Bmi.h"
#import "Person.h"
#import "Manage.h"

int main(int argc, const char *argv[]){

    Person *person = nil;
    int i;
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSError *error=nil;
    Manage *manage = [[Manage alloc] init];

    NSString *file = [NSString stringWithContentsOfFile:@"data.txt"
                                encoding:NSUTF8StringEncoding
                                error:&error ];

    NSArray *line = [file componentsSeparatedByString:@"n"];
    for(i = 0; i < [line count]; i++){
        if( [[line objectAtIndex:i] isEqualToString:@""]) {
            continue;
        }
        NSArray *col = [[line objectAtIndex:i] componentsSeparatedByString:@" "];
        person = [[Person alloc] initWithWeight:[[col objectAtIndex:1] doubleValue]
                                 height:[[col objectAtIndex:2] doubleValue]
                                 name:[col objectAtIndex:0]];
        [manage setPerson:person];
        [person release];
    }
    [manage showBestPerson];
    [manage recordBestPerson];
    [manage release];
    [pool drain];
    return 0;
}

増えているのは32行目です。呼び出しているだけですね。

結果確認

結果を見てみましょう。
Objc23-1

実行後にファイルの中身を確認しています。
名前、体重、身長、BMI値が書き込まれていますね。

まとめ

今回のまとめとしては
・NSStringクラスのwriteToFileメソッドを使用することでファイルへ文字列の書き込みができる
・ファイルの読み込みや書き込みの際には文字コードの指定ができ、列挙型の定数を使用して指定する
・文字列を作成する方法にはinitWithFormatメソッドを使う方法もある
といったところでしょうか。

  • このエントリーをはてなブックマークに追加

PAGE TOP