2010-10-12 111 views
1

我试图根据Dave DeLong here制作一个自定义的输入流,该输入流还允许通过NSURL从服务器读取数据。到目前为止,我有这样的做法,这对本地文件正常工作:NSFileHandle fileHandleForReadingFromURL有人可以向我解释这个吗?

@interface RJRStreamReader : NSObject { 
    @private 
    NSFileHandle *fileHandle; 
    NSStringEncoding encoding; 
    NSString *lineDelimiter; 
    unsigned long long currentOffset; 
    unsigned long long totalFileLength; 
    int chunkSize; 
} 

@property(readwrite, assign) NSStringEncoding encoding; 
@property(readwrite, assign) unsigned long long currentOffset; 
@property(readwrite, copy) NSString *lineDelimiter; 
@property(readwrite, assign) int chunkSize; 
@property(readonly) unsigned long long totalFileLength; 

-(id) initWithLocalFile:(NSString *) fileName; 

-(id) initWithURL:(NSURL *) remoteURL; 

-(id) initWithFileHandle:(NSFileHandle *) fh; 

-(NSString *) readToEnd; 

-(NSString *) readLine; 

/** 
@summary Reads a block of bytes from a stream 
@param blockLen the number of bytes to read 
@returns a string containing the data from the bytes read 
*/ 
-(NSString *) readBlock:(int) blockLen; 

@end 

,我的实:

@implementation RJRStreamReader 

@synthesize currentOffset, lineDelimiter, encoding, chunkSize, totalFileLength; 

-(id) initWithLocalFile:(NSString *)fileName 
{ 
    if (self = [super init]) 
    { 
     fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileName]; 
     if (fileHandle == nil) 
     { 
      [self release]; 
      return nil; 
     } 

     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     [fileHandle retain]; 
     currentOffset = 0ULL; 
     [fileHandle seekToEndOfFile]; 
     totalFileLength = [fileHandle offsetInFile]; 
    } 

    return self; 
} 

-(id) initWithURL:(NSURL *)remoteURL 
{ 
    if (self = [super init]) 
    { 
     NSError *err = nil; 
     fileHandle = [NSFileHandle fileHandleForReadingFromURL:remoteURL error:&err]; 
     if (err) 
     { 
      NSLog(@"Error occurred, aborting. Details: %@", err); 
      [self release]; 
      return nil; 
     } 

     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     [fileHandle retain]; 
     currentOffset = 0ULL; 
     [fileHandle seekToEndOfFile]; 
     totalFileLength = [fileHandle offsetInFile]; 
    } 

    return self; 
} 

-(id) initWithFileHandle:(NSFileHandle *) fh 
{ 
    if (self = [super init]) 
    { 
     fileHandle = fh; 
     if (!fh) 
     { 
      [self release]; 
      [NSException raise:@"FH cannot be nil!" format:@"FH cannot be nil!"]; 
      return nil; 
     } 

     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     [fileHandle retain]; 
     currentOffset = 0ULL; 
     [fileHandle seekToEndOfFile]; 
     totalFileLength = [fileHandle offsetInFile]; 
    } 

    return self; 
} 

-(NSString *) readBlock:(int)blockLen 
{ 
    if (currentOffset >= totalFileLength) { return nil; } 

    [fileHandle seekToFileOffset:currentOffset]; 
    NSData *data = [fileHandle readDataOfLength:blockLen]; 
    currentOffset += blockLen; 
    [fileHandle seekToFileOffset:currentOffset]; 

    return [[[NSString alloc] initWithData:data encoding:encoding] autorelease]; 
} 

-(NSString *) readLine 
{ 
    /* 
     if you want to see the code for this method, visit this link: 
     https://stackoverflow.com/questions/3707427/how-to-read-data-from-nsfilehandle-line-by-line 
     it is exactly the same 
    */ 
} 

-(NSString *) readToEnd 
{ 
    if (currentOffset >= totalFileLength) { return nil; } 

    [fileHandle seekToFileOffset:currentOffset]; 
    NSData *data = [fileHandle readDataToEndOfFile]; 
    currentOffset = totalFileLength; 
    [fileHandle seekToEndOfFile]; 

    return [[[NSString alloc] initWithData:data encoding:encoding] autorelease]; 
} 

-(void) dealloc 
{ 
    [fileHandle closeFile]; 
    [fileHandle release]; 
    [lineDelimiter release]; 
    [super dealloc]; 
} 

@end 

的问题是,当我尝试使用这样的:

RJRStreamReader *stream = [[RJRStreamReader alloc] initWithURL:[NSURL URLWithString:@"http://www.stackoverflow.com/robots.txt"]; 
NSString *s = [stream readToEnd]; 

s将始终为空,因为[NSFileHandle fileHandleForReadingFromURL:remoteURL]返回的NSFileHandle总是似乎返回零,没有任何错误。

这是我的代码中的错误还是他们的无证功能?

感谢

回答

1

OK,这是我的问题:

按照Doccoumentation

fileHandleForReadingFromURL:error: Returns a file handle initialized for reading the file, device, or named socket at the specified URL.

它不从服务器的URL,这使我这个方法阅读(我会喜欢它的人为我编辑这个,因为它需要延迟加载,优化等)

RJRStreamReader.h:

@interface RJRStreamReader : NSObject { 
    @private 
    NSData *data; 
    NSStringEncoding encoding; 
    NSString *lineDelimiter; 
    unsigned long long currentOffset; 
    unsigned long long totalFileLength; 
    int chunkSize; 
} 

@property(readwrite, assign) NSStringEncoding encoding; 
@property(readwrite, assign) unsigned long long currentOffset; 
@property(readwrite, copy) NSString *lineDelimiter; 
@property(readwrite, assign) int chunkSize; 
@property(readonly) unsigned long long totalFileLength; 

-(id) initWithLocalFile:(NSString *) fileName; 

-(id) initWithURL:(NSURL *) remoteURL; 

-(id) initWithFileHandle:(NSFileHandle *) fh; 

-(id) initWithData:(NSData *) theData; 

-(NSString *) readToEnd; 

-(NSString *) readLine; 

/** 
@summary Reads a block of bytes from a stream 
@param blockLen the number of bytes to read 
@returns a string containing the data from the bytes read 
*/ 
-(NSString *) readBlock:(int) blockLen; 

@end 

RJRStreamReader.m:

@implementation RJRStreamReader 

@synthesize currentOffset, lineDelimiter, encoding, chunkSize, totalFileLength; 

-(id) initWithLocalFile:(NSString *)fileName 
{ 
    if (self = [super init]) 
    { 
     NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileName]; 

     if (fileHandle == nil) 
     { 
      [self release]; 
      return nil; 
     } 

     data = [[fileHandle readDataToEndOfFile] retain]; 
     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     currentOffset = 0ULL; 
     [fileHandle seekToEndOfFile]; 
     totalFileLength = [fileHandle offsetInFile]; 
     [fileHandle closeFile]; 
    } 

    return self; 
} 

-(id) initWithURL:(NSURL *)remoteURL 
{ 
    if (self = [super init]) 
    { 
     NSError *err = nil; 
     NSURLResponse *resp = nil; 

     data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:remoteURL] returningResponse:&resp error:&err]; 

     if (err) 
     { 
      NSLog(@"Error occurred, aborting. Details: %@", err); 
      [self release]; 
      return nil; 
     } 

     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     [data retain]; 
     currentOffset = 0ULL; 
     totalFileLength = [data length]; 
    } 

    return self; 
} 

-(id) initWithFileHandle:(NSFileHandle *) fh 
{ 
    if (self = [super init]) 
    { 
     if (!fh) 
     { 
      [self release]; 
      [NSException raise:@"FH cannot be nil!" format:@"FH cannot be nil!"]; 
      return nil; 
     } 

     unsigned long long pos = [fh offsetInFile]; 

     data = [[fh readDataToEndOfFile] retain];  
     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     currentOffset = 0ULL; 
     [fh seekToEndOfFile]; 
     totalFileLength = [fh offsetInFile]; 
     [fh seekToFileOffset:pos]; 
    } 

    return self; 
} 

-(id) initWithData:(NSData *)theData 
{ 
    if (self = [super init]) 
    { 
     data = [theData retain];  
     chunkSize = 10; 
     encoding = NSUTF8StringEncoding; 
     lineDelimiter = [[NSString alloc] initWithString:@"\n"]; 
     currentOffset = 0ULL; 
     totalFileLength = [data length];   
    } 

    return self; 
} 

-(NSString *) readBlock:(int)blockLen 
{ 
    if (currentOffset >= totalFileLength) { return nil; } 

    NSData *tmpdata = [data subdataWithRange:NSMakeRange(currentOffset, blockLen)]; 
    currentOffset += blockLen; 

    return [[[NSString alloc] initWithData:tmpdata encoding:encoding] autorelease]; 
} 

-(NSString *) readLine 
{ 
    if (currentOffset >= totalFileLength) { return nil; } 

    NSData * newLineData = [lineDelimiter dataUsingEncoding:NSUTF8StringEncoding]; 
    //[fileHandle seekToFileOffset:currentOffset]; 
    NSMutableData * currentData = [[NSMutableData alloc] init]; 
    BOOL shouldReadMore = YES; 

    NSAutoreleasePool * readPool = [[NSAutoreleasePool alloc] init]; 
    while (shouldReadMore) { 
     if (currentOffset >= totalFileLength) { break; } 
     NSData *chunk = [data subdataWithRange:NSMakeRange(currentOffset, chunkSize)]; 
     NSRange newLineRange = [chunk rangeOfData_dd:newLineData]; 
     if (newLineRange.location != NSNotFound) { 

      //include the length so we can include the delimiter in the string 
      chunk = [chunk subdataWithRange:NSMakeRange(0, newLineRange.location)]; 
      shouldReadMore = NO; 
     } 
     [currentData appendData:chunk]; 
     currentOffset += [chunk length]; 
    } 
    [readPool release]; 

    NSString * line = [[NSString alloc] initWithData:currentData encoding:NSUTF8StringEncoding]; 
    [currentData release]; 
    return [line autorelease]; 
} 

-(NSString *) readToEnd 
{ 
    if (currentOffset >= totalFileLength) { return nil; } 

    NSData *tmpdata = [data subdataWithRange:NSMakeRange(currentOffset, totalFileLength - currentOffset)]; 
    currentOffset = totalFileLength; 

    return [[[NSString alloc] initWithData:tmpdata encoding:encoding] autorelease]; 
} 

-(void) dealloc 
{ 
    [data release]; 
    [lineDelimiter release]; 
    [super dealloc]; 
} 

@end 

注:我回答的唯一原因,我的问题是给别人用同样的问题:)

相关问题