如何在Dart中实现文件或目录复制到剪贴板?
在Dart中实现文件/目录复制到系统剪贴板(支持文件管理器粘贴)
Dart标准库的Clipboard类仅支持文本内容的剪贴操作,要实现文件/目录的复制(让系统文件管理器能通过Ctrl+V粘贴),必须调用平台原生的剪贴板API——不同操作系统对文件剪贴板的处理逻辑差异很大,以下分平台给出具体实现:
Windows平台
Windows通过CF_HDROP格式传递文件路径列表,使用win32包直接调用系统API实现:
- 先在
pubspec.yaml中添加依赖:
dependencies: win32: ^5.0.0
- 实现复制函数:
import 'dart:ffi'; import 'package:win32/win32.dart'; void copyFileOrDirectoryToClipboard(String path) { if (!OpenClipboard(NULL)) throw Exception('无法打开剪贴板'); try { EmptyClipboard(); // 分配内存存储HDROP结构和文件路径 final hGlobal = GlobalAlloc(GHND, sizeOf<DROPFILES>() + path.length * 2 + 2); final pDrop = GlobalLock(hGlobal); if (pDrop == nullptr) throw Exception('内存分配失败'); // 初始化DROPFILES头部 final dropStruct = pDrop.cast<DROPFILES>(); dropStruct.ref.pFiles = sizeOf<DROPFILES>(); dropStruct.ref.fWide = TRUE; // 写入宽字符格式的文件路径 final pFiles = pDrop.offsetBy(sizeOf<DROPFILES>()).cast<Uint16>(); for (var i = 0; i < path.length; i++) { pFiles[i] = path.codeUnitAt(i); } pFiles[path.length] = 0; // 单个路径结束符 pFiles[path.length + 1] = 0; // 路径列表结束符 GlobalUnlock(hGlobal); if (!SetClipboardData(CF_HDROP, hGlobal)) { GlobalFree(hGlobal); throw Exception('无法写入剪贴板数据'); } } finally { CloseClipboard(); } }
macOS平台
macOS通过NSPasteboard的NSFilenamesPboardType类型传递文件URL数组,用dart:ffi直接调用Cocoa API实现:
import 'dart:ffi'; import 'package:ffi/ffi.dart'; final cocoa = DynamicLibrary.open('/System/Library/Frameworks/AppKit.framework/AppKit'); typedef ObjCId = Pointer<Void>; typedef Sel = Pointer<Void>; // 绑定OC底层方法 ObjCId Function(ObjCId, Sel) objc_msgSend = cocoa .lookup<NativeFunction<ObjCId Function(ObjCId, Sel)>>('objc_msgSend') .asFunction(); ObjCId Function(Pointer<Utf8>) objc_getClass = cocoa .lookup<NativeFunction<ObjCId Function(Pointer<Utf8>)>>('objc_getClass') .asFunction(); Sel Function(Pointer<Utf8>) sel_registerName = cocoa .lookup<NativeFunction<Sel Function(Pointer<Utf8>)>>('sel_registerName') .asFunction(); void copyFileOrDirectoryToClipboard(String path) { // 获取系统剪贴板实例 final pasteboard = objc_msgSend( objc_getClass('NSPasteboard'.toNativeUtf8()), sel_registerName('generalPasteboard'.toNativeUtf8()) ); // 清空剪贴板原有内容 objc_msgSend(pasteboard, sel_registerName('clearContents'.toNativeUtf8())); // 创建文件URL对象 final fileUrl = objc_msgSend( objc_getClass('NSURL'.toNativeUtf8()), sel_registerName('fileURLWithPath:'.toNativeUtf8()), path.toNativeUtf8() ); // 将URL包装为数组 final urlArray = objc_msgSend( objc_getClass('NSArray'.toNativeUtf8()), sel_registerName('arrayWithObject:'.toNativeUtf8()), fileUrl ); // 设置剪贴板数据 objc_msgSend( pasteboard, sel_registerName('setData:forType:'.toNativeUtf8()), urlArray, objc_msgSend( objc_getClass('NSPasteboard'.toNativeUtf8()), sel_registerName('NSFilenamesPboardType'.toNativeUtf8()) ) ); }
Linux平台
Linux通过X11剪贴板的text/uri-list格式传递文件URI,最简单的方式是调用系统xclip命令:
import 'dart:io'; void copyFileOrDirectoryToClipboard(String path) { final fileUri = 'file://${Uri.encodeFull(path)}'; // 将URI写入系统剪贴板 Process.runSync('xclip', [ '-selection', 'clipboard', '-t', 'text/uri-list' ], input: fileUri); }
注意:系统需预先安装xclip,可通过sudo apt install xclip完成安装。
测试代码
void main(List<String> args) { final targetPath = "/some/path/file.txt"; // 替换为实际文件/目录路径 copyFileOrDirectoryToClipboard(targetPath); print('已复制到剪贴板,可在文件管理器中粘贴'); }
内容的提问来源于stack exchange,提问作者Lenny4
相关产品推荐
相关产品推荐

