Huynh httkt
Huynh httkt

Reputation: 19

How to get byte data from file in object c

I read file from fcntl(fd, F_GLOBAL_NOCACHE, 1); to read file from Disk not from Cache. After reading file, i can only get string data. Now i want to after reading file, i get byte data of file to NSMutableData. How can i do that? Thanks in advance.

   if (fd)

{
    fcntl(fd, F_GLOBAL_NOCACHE, 1);
    NSMutableData* myData = [[NSMutableData alloc] init];

    while(YES)
    {

        // store the length before addition
        NSUInteger previousLength = [myData length];

        // increase the length so we can write more bytes
        [myData increaseLengthBy:300];

        // read bytes from stream directly at the end of our data
        size_t len = fread([myData mutableBytes] + previousLength, 300, 1, fd);

        // set data length
        [myData setLength:previousLength + len];

        // if end-of-file exit the loop
        if (len == 0) {
            break;
        }
         [myData appendBytes:buffer length:len];
    }
    // use your 'myData'
    NSLog(@"dataFile: %@",myData);
    [myData release];

Please give me suggestions? thanks

UPDATE2: Now i have another problem: i want to read file direct from disk not from Cache. I used below code but it seem not work, it still read from Cache :

     NSString *url= [NSString stringWithFormat:@"%@/demo.abc"];

        const char *c_sd_url = [url UTF8String];
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
        FILE * fd = fopen(c_sd_url, "rb");

        if (fd)
        {

            fcntl(fd, F_GLOBAL_NOCACHE, 1);

            fseek(fd, 0, SEEK_END);
            long sz = ftell(fd);
            fseek(fd, 0, SEEK_SET);

            char *buf = malloc(sz);
            NSLog(@"before %s",buf);
            assert(buf != NULL);

            assert(fread(buf, sz, 1, fd) == 1);
            NSLog(@"after %s",buf);
            NSMutableData *data= [NSMutableData dataWithBytesNoCopy:buf length:sz freeWhenDone:YES];
            NSLog(@"%@",data);
}

I used fcntl(fd, F_GLOBAL_NOCACHE, 1); after fopen(). Please give me any suggestion. Thanks much

Upvotes: 0

Views: 6087

Answers (2)

Micha Mazaheri
Micha Mazaheri

Reputation: 3481

I guess Hot Licks is right, you probably want to simply use -[NSData dataWithContentsOfFile:], but in the case you want to use C level APIs, you can do:

#define MY_BUFFER_SIZE 1024

FILE * fd = fopen(c_sd_url, "rb");

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

char buffer[MY_BUFFER_SIZE];

if (fd)

{
    fcntl(fd, F_GLOBAL_NOCACHE, 1);

    // if you can predict the capacity it's better for performance
    NSMutableData* myData = [NSMutableData dataWithCapacity:1024];

    while(fgets(buffer, MY_BUFFER_SIZE, fd) != NULL)
    {
        [myData appendBytes:buffer length:strlen(buffer)];
    }
}

// use your 'myData'

[pool release];

Updated: to avoid useless copy of buffer data, and following H2CO3's comment:

It's better to avoid to write data to a buffer and then copy it to the NSMutableData, we can use -[NSData mutableBytes] to access directly the underlying C structure. Also, H2CO3 is completely right, using fread is much better since it gives us the length of the bytes read.

#define MY_BUFFER_SIZE 1024

FILE * fd = fopen(c_sd_url, "rb");

if (fd)
{
    fcntl(fd, F_GLOBAL_NOCACHE, 1);

    // if you can predict the capacity it's better for performance
    NSMutableData* myData = [[NSMutableData alloc] init];

    while(YES)
    {
        // store the length before addition
        NSUInteger previousLength = [myData length];

        // increase the length so we can write more bytes
        [myData increaseLengthBy:MY_BUFFER_SIZE];

        // read bytes from stream directly at the end of our data
        size_t len = fread([myData mutableBytes] + previousLength, 1, MY_BUFFER_SIZE, fd);

        // set data length
        [myData setLength:previousLength + len];

        // if end-of-file exit the loop
        if (len == 0) {
            break;
        }
    }

    // use your 'myData'
    NSLog(@"myData: %@", [[NSString alloc] initWithData:myData encoding:NSASCIIStringEncoding]);

    [myData release];
}

If you want to have a \0 terminated NSData, just add at the end:

[myData appendBytes:"\0" length:1];

Good luck ;)

Upvotes: 1

eonil
eonil

Reputation: 85975

char in C is guaranteed to be 1 byte at least by standard.

What is an unsigned char?

So you can treat char* as byte-array with proper size multiplication, and you can pass it to -[NSData initWithBytes:length:] method.

char buffer[300];
NSData* data0 = [[NSData alloc] initWithBytes:buffer length:300 * sizeof(char)];

There're several initializer methods, so check them out for your needs. See NSMutableData for procedural style use.

Or you can use NSData method as like @HotLicks said.

NSData* data0 = [NSData dataWithContentsOfFile:@"somefile" options:NSDataReadingUncached error:NULL];

Upvotes: 1

Related Questions