Read only a portion of a file from disk in objecti

2019-03-19 16:37发布

问题:

I am reading a very large file using a NSInputStream and sending them to a device in packets. If the receiver does not get a packet, I can send back to the sender with a packet number, representing the starting location in bytes of the packet missing.

I know an NSInputStream cannot rewind and grab the packet, but is there another way to grab the requested byte range without loading the entire large file into memory?

If there was a [NSData dataWithContentsOfFileAtPath:inRange] method, it would be perfect.

回答1:

You can rewind with NSInputStream:

[stream setProperty:[NSNumber numberWithInt:offset]
             forKey:NSStreamFileCurrentOffsetKey];


回答2:

I don't think there's a standard function that does that, but you could write one yourself, using a category and the C stdio API:

@interface NSData(DataWithContentsOfFileAtOffsetWithSize)
+ (NSData *) dataWithContentsOfFile:(NSString *)path atOffset:(off_t)offset withSize:(size_t)bytes;
@end

@implementation NSData(DataWithContentsOfFileAtOffsetWithSize)

+ (NSData *) dataWithContentsOfFile:(NSString *)path atOffset:(off_t)offset withSize:(size_t)bytes
{
  FILE *file = fopen([path UTF8String], "rb");
  if(file == NULL)
        return nil;

  void *data = malloc(bytes);  // check for NULL!
  fseeko(file, offset, SEEK_SET);
  fread(data, 1, bytes, file);  // check return value, in case read was short!
  fclose(file);

  // NSData takes ownership and will call free(data) when it's released
  return [NSData dataWithBytesNoCopy:data length:bytes];
}

@end

Then you can this:

// Read 100 bytes of data beginning at offset 500 from "somefile"
NSData *data = [NSData dataWithContentsOfFile:@"somefile" atOffset:500 withSize:100];