April 20, 2011 by

I noticed a strange lack of high performance I/O routines in Objective-C. All I see is:

  • Bulk I/O. E.g, contentsAtPath of NSFileManager or writeToFile of NSString. These are memory intensive and impractical for complex data structure.
  • Very low level buffer based I/O from NSFileHandle. This is not good for reading NSString, int and float.

It appears that most people fall back on C routines like fwrite and fscanf for the job. I decided roll out a class that handled the task of reading and writing NSString, int, float etc. I wanted to borrow Java’s readUTF and writeUTF methods for NSString. In fact, my implementation should be compatible to Java’s.

The implementation below reads and writes data using binary files. The class can improve upon more error checking. The readUTF method can be optimized by recycling the malloced buffer.

FileUtil.h

#import <Foundation/Foundation.h>


@interface FileUtil : NSObject {
    FILE *mFile;
}

- (BOOL) openRead: (NSString*) file;
- (BOOL) openWrite: (NSString*) file;
- (BOOL) openAppend: (NSString*) file;
- (void) close;
- (NSString*) readUTF;
- (void) writeUTF: (NSString*) string;
- (int) readInt;
- (void) writeInt: (int) value;
- (float) readFloat;
- (void) writeFloat: (float) value;

@end

FileUtil.m

#import "FileUtil.h"


@implementation FileUtil

- (FileUtil*) init {
    ;
    
    mFile = NULL;
    
    return self;
}

- (BOOL) openRead: (NSString*) file {
    ;
    mFile = fopen(, "rb");
    
    return mFile != NULL;
}

- (BOOL) openWrite: (NSString*) file {
    ;
    mFile = fopen(, "wb");    
    
    return mFile != NULL;
}

- (BOOL) openAppend: (NSString*) file {
    ;
    mFile = fopen(, "ab");
    
    return mFile != NULL;
}

- (void) close {
    if (mFile != NULL) {
        fclose(mFile);
        mFile = NULL;
    }
}

- (void)dealloc {
    ;
    ;
}

- (NSString*) readUTF {
    int length = 0;
    fread(&length, 2, 1, mFile); //Java's writeUTF writes length in 2 bytes only
    
    char *buff = malloc(length + 1); //Extra byte for ''
    fread(buff, 1, length, mFile);
    buff = '';
    
    NSString *string = ;
    
    free(buff);
    
    return string;
}

- (void) writeUTF: (NSString*) string {
    const char *utf = ;
    int length = strlen(utf);

    fwrite(&length, 2, 1, mFile); //Java's writeUTF writes length in 2 bytes only
    fwrite(utf, 1, length, mFile); //Write UTF-8 bytes
}

- (int) readInt {
    int i;
    
    fread(&i, sizeof(int), 1, mFile);
    
    return i;
}

- (void) writeInt: (int) value {
    fwrite(&value, sizeof(int), 1, mFile);
}

- (float) readFloat {
    float f;
    
    fread(&f, sizeof(float), 1, mFile);
    
    return f;
}

- (void) writeFloat: (float) value {
    fwrite(&value, sizeof(float), 1, mFile);
}

@end