NSFileHandle fileHandleForReadingFromURL может кто-нибудь объяснить это мне, пожалуйста?

Я пытаюсь создать настраиваемый поток ввода, основанный на том, что Dave DeLong здесь, который также позволяет считывать данные с сервера через NSURL. Пока у меня есть такой подход, который отлично подходит для локальных файлов:

@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: 
       /info/37342/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, возвращаемый [NSFileHandle fileHandleForReadingFromURL:remoteURL], всегда возвращает нуль без каких-либо ошибок.

Является ли это ошибкой в ​​моем коде или недокументированной функции?

Спасибо

Ответ 1

ОК, это моя проблема:

В соответствии с Doccoumentation

fileHandleForReadingFromURL: ошибка: Возвращает дескриптор файла, инициализированный для чтения файла, устройства или именованного сокета по указанному 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

ПРИМЕЧАНИЕ. Единственная причина, по которой я ответил на мой вопрос, - это проблемы с теми же проблемами:)