更改标题Infos二进制文件并将其写回

时间:2012-05-18 08:52:03

标签: objective-c xcode ipad file bytearray

我需要更改文档文件夹中文件的标题信息。 读取和写回二进制数据的最佳推荐方法是什么?

  1. 如何将数据从文件夹二进制文件读取到数组/流
  2. 如何将数据从数组/流写回本地iPad文档文件夹?
  3. Binary reading / writing in objective-c

3 个答案:

答案 0 :(得分:3)

主要包是只读的,你不能写任何东西。
为了写作,我们有文件目录 这将从主包中读取文件

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

已编辑
正如您所示,您的标题是1到10个字节..
你能不能告诉我一个人如何阅读你的文件,知道你的标题的确切长度是多少。它可以是1到10之间的2,3或7个。必须有一种方法来告诉它具有特定长度的标题,并且文件的其他部分也是如此。
没有这些信息我不认为你会知道你的标题,正文或页脚的大小。
如果我创建了这个文件,我可能会把标题的第一个字节作为标题的长度,这样任何人都可以读取标题,然后在读取标题之后,第一个字节的主体大小和页脚相同。

答案 1 :(得分:3)

如果你没有更具体的话,这个很难回答,但最有效的方法是根本不改变文件。

由于我们讨论的是iOS,除了您的应用程序本身之外,没有文件系统级别的文档访问权限。那么为什么不在应用程序范围的元数据存储(例如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

答案 2 :(得分:1)

C流非常简单:FILE*fopenfseekofreadfwrite

如果你的数据只有266个字节,那么它足够小,你可以使用[NSMutableData dataWithContentsOfURL:url]全部读取它,然后使用NSData {{1}将其写回(覆盖整个文件) }} 方法。但是,您需要避免使用较大文件的此方法。此时,您将需要使用C接口(上图),或考虑write*NSFileHandleNSInputStreamNSOutputStreamCFReadStream等。