将 FileURL 的名称写入粘贴板

Writing FileURL's name to Pasteboard

我想使用 [pasteboard writeObjects:pasteboardArray]; 将一些文件URL 写入通用粘贴板,其中 pasteboard 是通用粘贴板的对象,pasteboardArray 是 NS 的 NSArray URL的。它像

这样在粘贴板上写 url

文件://localhost/Usr/

文件://localhost/Vol/

...等等

我想把这些URL写成如下

用户名

成交量

..等等

即只有 file/Directory 的名称,因为系统在复制任何 file/Directory 时所做的。

对于粘贴板上的每个项目,可以有多种类型的数据。当您将 NSURL 写入粘贴板时,它会放入诸如 public.file-url(URL 作为 UTF-8 文本)、NSFilenamesPboardType(文件路径字符串数组,序列化为 XML 属性 列表),"Apple URL pasteboard type"(文件 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: and/or -addTypes:owner: 后跟 -set...:forType:(例如 -setString:forType:)的旧方法。或者它可能正在使用其 -set...:forType: 方法构建具有所需类型和数据的 NSPasteboardItem 实例,然后将这些项目写入粘贴板。

根据您的需要,这样做可能就足够了:

[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 的显示名称,用回车符 return 分隔(这就是 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 复制文件时应用程序获得的内容略有不同,其中字符串与回车符 return 连接。某些应用可能无法很好地应对这种差异。

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。欢迎任何更好的解决方案...