Frage

Ich versuche, einen maßgeschneiderten Eingangsstrom von dem von Dave DeLong hier dass ermöglicht auch Daten von einem Server über NSURL lesen. Bisher habe ich diesen Ansatz, der gut für lokale Dateien funktioniert:

@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

Und meine Implementierung:

@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

Das Problem ist, wenn ich versuche, es so zu verwenden:

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

s wird immer leer sein, weil die NSFileHandle von [NSFileHandle fileHandleForReadingFromURL:remoteURL] zurück scheint immer null zurück, ohne Fehler.

Ist das ein Fehler in meinem Code oder eine nicht dokumentierte Funktion von ihnen?

Danke

War es hilfreich?

Lösung

OK, das ist mein Problem:

Nach dem Dokumentation

  

fileHandleForReadingFromURL: error:   Gibt eine Datei-Handle zum Lesen der Datei, ein Geräts initialisiert oder Named-Buchse an der angegebenen URL.

Es ist nicht von einem Server URL lesen, die mich zu diesem Ansatz führte (ich würde es für die Menschen zu bearbeiten, wie dies für mich, da es ein träges Laden braucht, Optimierung, etc.)

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top