将FileURL的名称写入Pasteboard

时间:2015-02-13 16:29:35

标签: objective-c macos cocoa copy-paste nspasteboard

我想使用[pasteboard writeObjects:pasteboardArray];将一些fileURL写入常规粘贴板,其中pasteboard是普通粘贴板的对象,pasteboardArray是NSURL的NSArray。它将网址写在粘贴板上,如

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

文件://本地主机/体积/

......等等

我想把这些网址写成以下

USR

..等等

,即只有系统在复制任何文件/目录时所执行的文件/目录名称。

2 个答案:

答案 0 :(得分:3)

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

当您在Finder中复制文件时,它会放置许多相同的类型,尽管它似乎首先将URL转换为文件引用URL。此外,它将文件的图标设置为ICNS和TIFF图像。但是,public.utf8-plain-text类型只包含文件名,而不包含其URL。该字符串也存在类型public.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];
}

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

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

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

答案 1 :(得分: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。欢迎任何更好的解决方案...