2012-05-18 4 views

답변

3

이 하나, 당신은 좀 더 구체적인없이 대답하기 어렵다하지만 (위) C 인터페이스를 사용하거나 고려해야 할 것 이 작업을 수행하는 가장 효율적인 방법은 틀림없이 에 파일을 전혀 변경하지 않을 것입니다. 우리는 아이폰 OS에 대해 얘기하고 있기 때문에

은 떨어져 응용 프로그램 자체에서 해당 문서에는 파일 시스템 수준의 액세스가 없다. 그런데 왜 당신이 (예를 들어, iTunes 또는 iPhoto를 할 같은) 응용 프로그램 전체 메타 데이터 저장소에 파일과 연결 만 수출시 실제 파일 헤더를 인터리브 할 추가/사용자 정의 헤더 데이터를 저장하지?

관계없이 C 레벨 파일 기능을 사용하여 데이터를 변경할 수있는 강력한 이유는 없습니다. NSInputStream은 스트리밍 파일 읽기 액세스 및 NSOutputStream을 사용하여 데이터를 스트리밍하는 데 사용할 수 있습니다. 파일.

당신은 가능성이 같은 API로 끝날 것 위에서 당신은 내 제안에 갈 경우 :

typedef void (^DataExportHandler)(NSData *resultData, NSError *exportError); 

@interface DataStore (FileExport) 

/** If you wanted to abort the export, you could pass the stream into the `abort…:`-method 
@param identifier Something that you use internally to manage your stored files. 
@param error  For good measure… 
@return The export stream for the object or `nil` if an error occurred. 
*/ 
- (NSInputStream *)exportStreamForObjectWithIdentifier:(id)identifier error:(NSError * __autoreleasing*)error; 

/** If your data are mostly small, it may be more convenient to not consume the exports as streams but as BLOBs, if the sizes vary you could implement this as a convenience… 
@param identifier Equivalent to the identifier in the method above 
@param handler  Callback that is invoked once some time later when the export finished or failed. **Must not** be `nil`. 
*/ 
@return A cancellation token. 
- (id)asynchronouslyExportDataForObjectWithIdentifier:(id)identifier resultHandler:(DataExportHandler)handler; 

/** 
@param exportToken Either a stream from the first method or a token returned from the second one. 
*/ 
- (void)abortAsynchronousExportWithToken:(id)exportToken; 

@end 

ARC되어 있다고 가정하고, 원본과 함께 추가 메타 데이터를 인터리브하기 위해 무엇을해야 모르고, 여기 구현의 상용구 부분이 일 수 있습니다.처럼 보입니다.

rawDataStream에 대한 위임을 구현하여 원본 파일의 데이터를 사용하고 추가 정보로 헤더를 인터리빙하는 쇠고기는 여기에 나와 있지 않은 부분에 분명하게 나와 있습니다. 이것은 아마도 별도의 클래스로 분해되어야하지만, 데이터 저장소가 NSStreamDelegate 콜백을 적절하게 구현한다는 것을 암시했습니다. 그냥 파일의 나머지 부분을 통과하려는 헤더 후

...

/// Scribble of another helper class that can be used whenever one needs to consume a stream for its aggregate data: 
@interface _StreamConsumer : NSObject <NSStreamDelegate> { 
    NSInputStream *_stream; 
    DataExportHandler _handler; 
    NSMutableData *_data; 
} 

// initiate the data, set itself as the stream’s delegate, open and schedule the stream in a runloop. 
- (id)initWithInputStream:(NSInputStream *)stream resultHandler:(DataExportHandler)handler; 

// forward the close to the stream 
- (void)close; 

// Implementation of the stream delegate callbacks can be more or less copy-pasted from Apple’s Stream Programming Guide (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Streams/Streams.html) 
@end 

@implementation DataStore (FileExport) 

- (id)asynchronouslyExportDataForObjectWithIdentifier:(id)someUniqueIdentifier resultHandler:(void (^)(NSData *fileData, NSError *exportError)) 
{ 
    NSParameterAssert(handler); 
    handler = [handler copy]; 

    NSError *setupError; 
    NSInputStream *exportStream = [self exportStreamForObjectWithIdentifier:someUniqueIdentifier error:&setupError]; 
    if (!exportStream) 
    { 
     dispatch_async(dispatch_get_current_queue(), ^{ 
      handler(nil, setupError); 
     }); 

     return nil; 
    } 

    _StreamConsumer *helper = [[_StreamConsumer alloc] initWithStream:exportStream resultHandler:handler]; 

    return helper; 
} 

- (void)abortAsynchronousExportWithToken:(id)exportToken 
{ 
    [exportToken close]; 
} 

- (NSInputStream *)exportStreamForObjectWithIdentifier:(id)identifier error:(NSError * __autoreleasing*)error 
{ 
    // do your thing to retrieve the URL to the actual data-file and then: 
    NSInputStream *rawDataStream = [NSInputStream inputStreamWithURL:rawFileURL]; 

    if (!rawDataStream) 
    { 
     // populate the error in a meaningful way 
     return nil; 
    } 

    CFReadStream cfExportStream; 
    CFWriteStream cfBuffer; 
    CFStreamCreateBoundPair(kCFAllocatorDefault, &cfExportStream, &cfBuffer, someValueYouHaveTuned); 

    if (!cfExportStream || !cfBuffer) 
    { 
     // error population 
     return nil; 
    } 

    NSInputStream *exportStream = (__bridge_transfer NSInputStream *)cfExportStream; 

    // HACKITY HACK: In reality, you’d want this stuff separated! 
    // For the sake of simplicity, take the responsibility for that ourselves 
    _exportBuffer = (__bridge_transfer NSOutputStream *)cfBuffer; 

    rawDataStream.delegate = self; 
    [rawDataStream open]; 
    [rawDataStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunloopDefaultMode]; 
    // END: HACKITY HACK 

    return exportStream; 
} 

@end 
+0

안녕하세요. 답변 해주셔서 감사합니다. 어쩌면 시작 인덱스가 11 인 바이트를 읽은 샘플을 어디에 쓸 수 있는지 보여 줄 수 있습니까? 바이트 인덱스 255까지 읽을 때까지? – Nasenbaer

3

홈페이지 번들은 읽기 전용 당신이 거기에 아무것도 쓸 수있다.
작성을 위해 문서 디렉토리가 있습니다.
당신이 당신의 헤더는 1에서 10 바이트입니다 표시된 것처럼이
편집 주요 번들

NSString *path= [[NSBundle mainBundle] pathForResource:@"myFile" ofType:@"txt"]; 

에서 파일을 읽습니다 ..
당신은 사람이 어떻게 생각 말해 수있는 파일을 읽는 중 머리글의 길이가 정확히 얼마인지 알고 있습니다. 1에서 10 사이의 값은 2, 3 또는 7이 될 수 있습니다. 특정 길이의 헤더가 있고 파일의 다른 부분과 동일한 경우를 알 수있는 방법이 있어야합니다.
이 정보가 없으면 머리말, 본문 또는 바닥 글의 크기를 알 수 없다고 생각합니다.
나는 어떤 하나의 헤더를 읽고 몸의 크기와 바닥 글 같은 위해 만든 첫 번째 바이트 그 후 헤더를 읽은 후 수 있도록 내가 헤더의 길이와 헤더의 첫 번째 바이트를 넣어 수도이 파일을 만든 경우.

+0

감사합니다. 그것은 질문의 일부에 대한 답입니다. 파일의 읽기/쓰기와 관련된 두 가지 질문에 대한 답을 줄 수 있습니까? – Nasenbaer

+0

답변을 업데이트 해 주셔서 감사합니다. 그러나 3 가지 부분으로 파일을 분할하는 가장 큰 비밀은 여전히 ​​명확하지 않습니다. – Nasenbaer

1

C 스트림은 충분히 쉽게 : FILE*, fopen, fseeko, fread, fwrite.

데이터의 단지 266 바이트, 즉 방금 [NSMutableData dataWithContentsOfURL:url]를 사용하여 모두 읽은 다음 NSDatawrite* 방법을 사용하여 (전체 파일을 덮어 쓰기) 다시 그것을 밖으로 쓸 수있을만큼 작은 있다면. 그러나 더 큰 파일을 사용하는 경우에는이 방법을 사용하지 않는 것이 좋습니다. 그 시점에서, 당신은 NSFileHandle, NSInputStream, NSOutputStream, CFReadStream, CFWriteStream, 등

관련 문제