You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中实现文件或目录复制到剪贴板?

在Dart中实现文件/目录复制到系统剪贴板(支持文件管理器粘贴)

Dart标准库的Clipboard类仅支持文本内容的剪贴操作,要实现文件/目录的复制(让系统文件管理器能通过Ctrl+V粘贴),必须调用平台原生的剪贴板API——不同操作系统对文件剪贴板的处理逻辑差异很大,以下分平台给出具体实现:

Windows平台

Windows通过CF_HDROP格式传递文件路径列表,使用win32包直接调用系统API实现:

  1. 先在pubspec.yaml中添加依赖:
dependencies:
  win32: ^5.0.0
  1. 实现复制函数:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:37:02