代码之家  ›  专栏  ›  技术社区  ›  Jaanus

为什么将文件保存到NSDocument中会创建同一文件的名称中带有奇怪字符的版本?

  •  1
  • Jaanus  · 技术社区  · 11 年前

    我正在开发一个基于NSDocument的应用程序,其文档类型是包含一堆文件的包包。我这样保存它:

    - (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
    {
        if (!self.documentFileWrapper) {
            NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
            [self setDocumentFileWrapper:documentFileWrapper];
        }
    
        NSFileWrapper *defaultWrapper = [self.documentFileWrapper.fileWrappers objectForKey:@"default"];
        if (!defaultWrapper) {
            defaultWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
            [defaultWrapper setPreferredFilename:@"someFile.ext"];
            [self.documentFileWrapper addFileWrapper:defaultWrapper];
        }
    
        [defaultWrapper addRegularFileWithContents: ... some computed content for the file ... preferredFilename:@"someFile.ext"];
    
        return self.documentFileWrapper;
    }
    

    换句话说,在捆绑包中,创建一个文件夹默认值,并将someFile.ext和一些内容保存到其中。

    现在,问题来了。当我去查看实际保存在磁盘上的内容时,我会看到:

    screenshot

    每次保存文件时,NSDocument包装器似乎都会创建资源的某个版本副本。我不想要版本化的克隆,我只想要包含最新内容的普通文件。

    版本化资源来自何处?这是怎么回事?我该看医生吗?

    2 回复  |  直到 11 年前
        1
  •  2
  •   Erhannis    11 年前

    好吧,我想我想通了。事实证明,这实际上不是版本控制问题。似乎每次都只是添加一个新文件。首先,请注意几点。

    1. 您似乎不是在包中创建文件,而是在包中的“包含文件的目录”。这是你打算做的吗?
    2. 看起来,如果目录“default”不存在,您可以创建并使用一个目录“someFile.ext”,这意味着下次它将创建一个带有奇怪前缀的新目录。然而,我从你的截图中看到,你已经有了一个“默认”目录,这意味着这不是你的问题。

    现在,你的实际问题是:根据 this documentation , addRegularFileWithContents 使用您的首选文件名创建新文件, 除非 目录( defaultWrapper )已经包含具有该名称的文件(基本上)。如果已经存在,它将创建一个带有前缀的新文件。 添加包含内容的常规文件 返回一个引用创建的NSFileWrapper的标识字符串(我认为是文件名)。

    因此,发生的情况是,每次您保存文件时,它都会看到已经有一个同名文件,并创建一个新的前缀文件。解决此问题的一种方法是将返回的NSString 添加包含内容的常规文件 ,然后当您去保存时,请检查 默认包装器 并删除与存储的NSString关联的NSFileWrapper(如果有),然后像正常一样添加该文件。我修改了您的代码如下:

    @interface TestDocument () // Relevant part of my test class.  Note `wrapperFileName`.
    
    @property (nonatomic, strong) NSFileWrapper *documentFileWrapper;
    @property (nonatomic, strong) NSString *wrapperFileName;
    
    @end
    
    
    
    - (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
    {
        if (!self.documentFileWrapper) {
            NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
            [self setDocumentFileWrapper:documentFileWrapper];
        }
    
        NSFileWrapper *defaultWrapper = [self.documentFileWrapper.fileWrappers objectForKey:@"default"];
        if (!defaultWrapper) {
            defaultWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
            [defaultWrapper setPreferredFilename:@"default"];
            [self.documentFileWrapper addFileWrapper:defaultWrapper];
        } else if (self.wrapperFileName) {
            [defaultWrapper removeFileWrapper:[[defaultWrapper fileWrappers] objectForKey:self.wrapperFileName]];
        }
    
        self.wrapperFileName = [defaultWrapper addRegularFileWithContents:[@"blah blah" dataUsingEncoding:NSUTF8StringEncoding] preferredFilename:@"someFile.txt"];
        return self.documentFileWrapper;
    }
    
    1. 我改变了 默认包装器 的首选文件名为“默认”,正如我所想的那样。
    2. 我添加了一个 if 删除先前保存的文件(如果存在)的块。
    3. 我已经让它存储了新的NSFileWrapper文件名,以便下次在#2中使用。

    在这些更改之后,程序演示了我认为是您所期望的行为:一个目录包含一个文件,即使保存了多次。注意,即使在 preservesVersions 返回 YES 。我不确定它的版本存储在哪里,但我没有看到它们。

        2
  •  1
  •   Danish Iqbal    11 年前

    您可以实现-writeSafely,以便它直接调用-writeToURL: 实现-writeToURL:,以便它调用-fileWrapperOfType:,然后将其写入URL 原子地,原子地

    也就是说,你将通过让NSFileWrapper来承担原子保存的责任。这样,包装器就可以很好地跟踪文件真正到达的位置。

    Source