2

我想使用[pasteboard writeObjects:pasteboardArray];wherepasteboard是通用粘贴板的对象并且pasteboardArray是 NSURL 的 NSArray 将一些文件 URL 写入通用粘贴板。它在粘贴板上写网址,例如

文件://本地主机/用户/

文件://本地主机/卷/

...等等

我想把这些 URL 写成如下

用户

..等等

即只有文件/目录的名称,就像系统在复制任何文件/目录时所做的那样。

4

2 回答 2

3

对于粘贴板上的每个项目,可以有多种类型的数据。当您将 an 写入NSURL粘贴板时,它会放入诸如public.file-url(UTF-8 文本的 URL)、NSFilenamesPboardType(文件路径字符串数组,序列化为 XML 属性列表)、“Apple URL 粘贴板类型”(文件数组URL 字符串,序列化为 XML 属性列表)和public.utf8-plain-text(作为 UTF-8 文本的 URL)。

当您在 Finder 中复制文件时,它会放置许多相同的类型,尽管它似乎首先将 URL 转换为文件引用 URL。此外,它将文件的图标作为 ICNS 和 TIFF 图像。但是,该public.utf8-plain-text类型只有文件的名称,而不是其 URL。该字符串也存在于 typepublic.utf16-plain-text中。

因此,据推测,Finder 不仅仅是-writeObjects:用来填充粘贴板。它可能使用-declareTypes:owner:和/或-addTypes:owner:后跟-set...:forType:(例如-setString:forType:)的旧方法。或者它可能正在NSPasteboardItem使用其方法构造具有所需类型和数据的实例,-set...:forType:然后将这些项目写入粘贴板。

对于您的需要,这样做可能就足够了:

[pasteboard writeObjects:arrayOfURLs];
NSMutableString* names = [NSMutableString string];
for (NSURL* url in arrayOfURLs)
{
    NSString* name;
    if ([url getResourceValue:&name forKey:NSURLLocalizedNameKey error:NULL])
    {
        if (names.length)
            [names appendString:@"\r"];
        [names appendString:name];
    }
}
if (names.length)
{
    [pasteboard addTypes:@[(__bridge NSString*)kUTTypeUTF8PlainText] owner:nil];
    [pasteboard setString:names forType:(__bridge NSString*)kUTTypeUTF8PlainText];
 }

注意:当您将多个 URL 写入粘贴板时,会有多个项目,每个项目都有多种类型。但是,某些类型是针对整个集合的,并且仅适用于第一项。普通字符串类型和NSFilenamesPboardType是这样的。上面的代码将纯字符串放在第一项上,并包括所有由回车分隔的 URL 的显示名称(这是 Finder 所做的)。

综上所述,尚不清楚您是否希望粘贴板包含URL 的显示名称,而不是任何表示形式的 URL 本身。在这种情况下,只需从 URL 的显示名称创建一个字符串数组并将该数组传递给-writeObjects:您就完成了。


更新:

我找到了一种更接近 Finder 功能的方法,同时采取了一些捷径:

NSMutableArray* arrayOfPaths = [arrayOfURLs valueForKey:@"path"];
[pasteboard setPropertyList:arrayOfPaths forType:NSFilenamesPboardType];

NSMutableString* names = [NSMutableString string];
BOOL first = YES;
for (NSURL* url in arrayOfURLs)
{
    NSString* name;
    if (![url getResourceValue:&name forKey:NSURLLocalizedNameKey error:NULL])
        name = @"";

    if (first)
        first = NO;
    else
        [names appendString:@"\r"];
    [names appendString:name];
}
if (names.length)
{
    [pasteboard addTypes:@[(__bridge NSString*)kUTTypeUTF8PlainText] owner:nil];
    [pasteboard setString:names forType:(__bridge NSString*)kUTTypeUTF8PlainText];
}

当您为 type 设置数据时NSFilenamesPboardType,Cocoa 会自动设置多项,数组中的每个元素对应一项。第二个和后续的每个都只有一个 type public.file-url。第一项具有该类型以及 Finder 放在粘贴板上的大多数其他类型,而不是图像类型。然后,只需在第一项上设置字符串值即可。

包含类型很重要,NSFilenamesPboardType因为这是在添加对多个粘贴板项目的支持之前在粘贴板上表示多个文件的方式。一些应用程序可能仍然依赖于此。

此外,如果您分别为每个项目提供字符串数据(如您自己的答案中所做的那样),那么一个从整个粘贴板(即[pasteboard stringForType:NSStringPboardType])请求字符串的应用程序会将它们与换行符连接起来。这与从 Finder 复制文件时应用程序获得的结果略有不同,其中字符串与回车连接。一些应用程序可能无法很好地应对这种差异。

于 2015-02-13T17:45:12.640 回答
1
NSMutableArray *archive=[NSMutableArray array];
                for (int i = 0; i < [pasteboardArray count]; i++) {
                    NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
                    NSURL *url = [pasteboardArray objectAtIndex:i];
                    if (url != nil) {
                        [item setString:[url lastPathComponent] forType:(__bridge NSString*)kUTTypeUTF8PlainText];
                        NSString *str = [NSString stringWithFormat:@"%@",url];
                        [item setData:[str dataUsingEncoding:NSUTF8StringEncoding] forType:(__bridge NSString*)kUTTypeFileURL];
                    }
                    [archive addObject:item];
                }
[pasteboard writeObjects:archive];

这对我有用,哪里pasteboard是一般粘贴板的对象,pasteboardArray是 NSURL 的 NSArray。欢迎任何更好的解决方案......

于 2015-02-14T12:57:06.477 回答