Чтение NSMutableData в виде потока - PullRequest
0 голосов
/ 25 ноября 2010

У меня есть экземпляр NSMutableData, и я хочу читать из него с использованием входного потока (аналогично ByteArrayInputStream Java).

Я заметил, что CFReadStream имеет метод initForReadingWithData, но я не смогвыясните, как его использовать.

Кто-нибудь может предоставить примерный бит о том, как его использовать или как иначе получить поток ввода в память?

Ответы [ 3 ]

0 голосов
/ 28 ноября 2010

Это решение, которое я достиг:

NSMutableData *msg;
CFReadStreamRef in = CFReadStreamCreateWithBytesNoCopy(nil, [msg mutableBytes], [_msg length], kCFAllocatorNull);
CFReadStreamOpen(in);
// read here as stream using CFReadStreamRead
CFRelease(in);
0 голосов
/ 23 ноября 2015

Ответ на этот вопрос зависит от того, хотите ли вы прочитать данные и удалить их аналогично тому, как NSStream управляет своими данными, или если вы хотите выполнить мягкое чтение и хотите иметь возможность перечитывать данные снова .

Для первого подхода самый простой способ - создать категорию NSMutableData, которая будет принимать в качестве параметра количество считываемых байтов, а затем будет возвращать данные после их удаления.

#import "NSMutableData+Queue.h"

@implementation NSMutableData (Queue)

- (NSData *)read:(NSUInteger)length
{
    if(length <= self.length && length > 0)
    {
        NSData *data = [self subdataWithRange:NSMakeRange(0, length)];
        [self replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
        return data;
    }

    return nil;
}

- (void)removeBytes:(NSUInteger)length
{
    if(length <= self.length && length > 0)
    {
        [self replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
    }
}

@end

Второй подход заключается в написании класса, который управляет объектом NSData и выполняет мягкое чтение для него, сохраняя при этом ссылку на его смещение.

//
//  CUDataReader.m
//  Test
//
//  Created by Abel Duarte on 10/28/15.
//  Copyright © 2015 Abel Duarte. All rights reserved.
//

#import "CUDataReader.h"

@interface CUDataReader()
@property (nonatomic, assign) CUDataReaderEndianness endianness;
@property (nonatomic, retain) NSData *data;
@end

@implementation CUDataReader

#pragma mark - Init

- (id)initWithData:(NSData *)data
{
    self = [super init];
    if(self)
    {
        self.data = data;
        self.offset = 0;
        self.endianness = CUDataReaderDefaultEndian;
    }
    return self;
}

+ (id)dataReaderWithData:(NSData *)data
{
    return [[CUDataReader alloc] initWithData:data];
}

- (void)dealloc
{
    self.data = nil;
}

#pragma mark - Read

- (NSData *)read:(NSUInteger)length
{
    NSUInteger readLength = self.offset + length;

    if(readLength <= self.data.length && length > 0)
    {
        NSData *data = [self.data subdataWithRange:NSMakeRange(self.offset, length)];
        self.offset += length;

        return data;
    }

    return nil;
}

- (NSData *)readUntilData:(NSData *)data
{
    NSRange dataRange = [self.data rangeOfData:data
                                       options:0
                                         range:NSMakeRange(self.offset, self.data.length - self.offset)];

    if(dataRange.location != NSNotFound)
    {
        NSUInteger length = dataRange.location - self.offset;
        return [self read:length];
    }

    return nil;
}

- (NSData *)readUntilDelimeter:(char)delimeter
{
    NSData *data = [NSData dataWithBytes:&delimeter length:1];
    return [self readUntilData:data];
}

#pragma mark - Endianess

- (void)setEndianness:(CUDataReaderEndianness)endianness
{
    _endianness = endianness;
}

- (NSData *)endiannessDecodedData:(NSData *)data
{
    if(self.endianness == CUDataReaderLittleEndian)
    {
        return data;
    }
    else
    {
        NSMutableData *endiannessDecodedData = [NSMutableData data];

        NSUInteger length = data.length;
        char *bytes = (char *)[data bytes];

        for(NSInteger i = length - 1; i >= 0; i--)
        {
            char *byte = bytes + i;
            [endiannessDecodedData appendBytes:byte length:1];
        }

        return endiannessDecodedData;
    }

    return data;
}

#pragma mark - Type utilities

- (BOOL)readBoolean
{
    NSUInteger length = sizeof(BOOL);
    return *(BOOL *)[[self endiannessDecodedData:[self read:length]] bytes];
}

- (char)readCharacter
{
    NSUInteger length = sizeof(char);
    return *(char *)[[self endiannessDecodedData:[self read:length]] bytes];
}

- (short)readShort
{
    NSUInteger length = sizeof(short);
    return *(short *)[[self endiannessDecodedData:[self read:length]] bytes];
}

- (int)readInteger
{
    NSUInteger length = sizeof(int);
    return *(int *)[[self endiannessDecodedData:[self read:length]] bytes];
}

- (float)readFloat
{
    NSUInteger length = sizeof(float);
    return *(float *)[[self endiannessDecodedData:[self read:length]] bytes];
}

- (double)readDouble
{
    NSUInteger length = sizeof(double);
    return *(double *)[[self endiannessDecodedData:[self read:length]] bytes];
}

- (long)readLong
{
    NSUInteger length = sizeof(long);
    return *(long *)[[self endiannessDecodedData:[self read:length]] bytes];
}

#pragma mark - Offset

- (void)rewind
{
    self.offset = 0;
}

- (void)rewind:(NSUInteger)length
{
    if(length <= self.offset)
    {
        self.offset -= length;
    }
    else
    {
        self.offset = 0;
    }
}

- (void)setOffset:(NSUInteger)offset
{
    if(offset <= self.data.length)
        _offset = offset;
}

- (void)skip:(NSUInteger)offset
{
    NSUInteger x = self.offset + offset;
    [self setOffset:x];
}

- (NSUInteger)bytesRemaining
{
    return self.data.length - self.offset;
}

@end

Пожалуйста, посмотрите на https://github.com/abelduarte/CoreUtilities для получения дополнительной информации.

0 голосов
/ 25 ноября 2010

Я заметил, что CFReadStream имеет метод initForReadingWithData,…

А?CFReadStream не имеет методов;у него есть функции.NSInputStream имеет initWithData:.

. Для NSInputStream вы должны быть делегатом потока, открывать поток и отвечать на его сообщения делегата.Большая часть этого находится в абстрактном классе NSStream , который является суперклассом как NSInputStream, так и NSOutputStream.

Вы можете найти CFReadStream более простым в использовании, поскольку он позволяет вампросто вызовите функцию для чтения непосредственно из потока, без необходимости соответствовать асинхронным требованиям «не звони мне».Для чтения из сети, я бы посоветовал против этого, но, поскольку вы читаете из буфера памяти, это должно быть безвредно.

Тем не менее, главная причина, чтобы создать поток, а не просто пройти черезБайт сам должен передать его чему-то, что принимает любой поток, в том числе тот, который может читать из сети.Если вы реализуете эту сторону, вы должны делать это асинхронно.

...