大家好,我是何三,独立开发者。
你有没有想过,当你在 Word 里复制一张图片,然后粘贴到微信聊天框时,为什么图片能完美呈现?当你从网页复制一段文字,粘贴到记事本时,格式消失了但内容还在?这一切的背后,都是剪切板在"默默付出"。
今天我们就来深入了解一下剪切板支持的数据类型,以及如何用 Python 来操作这些数据。
什么是剪切板?
剪切板(Clipboard)是操作系统提供的一个临时存储区域,用于在应用程序之间传递数据。它就像一个"中转站",当你执行复制操作时,数据被放入这个中转站;当你执行粘贴操作时,数据从中转站被取出。
但问题来了:不同的应用程序需要的数据格式不一样。比如: - 记事本只需要纯文本 - Word 需要带格式的富文本 - 画图工具需要图片数据 - Excel 需要表格数据
剪切板是如何做到"一份数据,多种用途"的呢?答案就是:支持多种数据类型。
剪切板支持的主要数据类型
1. 纯文本格式(Text)
这是最基础、最通用的格式。几乎所有的应用程序都支持纯文本的复制粘贴。
常见的文本格式标识:
- CF_TEXT (1):标准 ANSI 文本
- CF_UNICODETEXT (13):Unicode 文本(现代应用首选)
- CF_OEMTEXT (7):OEM 字符集文本
2. 位图格式(Bitmap)
用于存储图片数据,这是最基础的图片格式。
常见标识:
- CF_BITMAP (2):设备相关的位图
- CF_DIB (8):设备无关位图
- CF_DIBV5 (17):扩展的设备无关位图
3. 富文本格式(Rich Text Format)
当你从 Word 复制内容时,剪切板会同时存储多种格式: - 纯文本(给记事本用) - RTF 格式(给支持富文本的应用用) - HTML 格式(给网页编辑器用)
4. HTML 格式
现代应用常常支持 HTML 格式的复制粘贴,保留网页的结构和样式。
5. 文件列表格式
当你复制文件时,剪切板存储的是文件路径列表。
标识:
- CF_HDROP (15):文件拖放列表
6. 自定义格式
应用程序可以注册自己的剪切板格式,用于特殊数据的传递。

用 Python 操作剪切板
了解了剪切板的数据类型,接下来我们用 Python 来实际操作一下。这里主要介绍两种常用的库:pyperclip 和 win32clipboard。

安装依赖
pip install pyperclip pywin32
基础文本操作(使用 pyperclip)
pyperclip 是最简单的剪切板操作库,适合处理纯文本:
import pyperclip
# 复制文本到剪切板
pyperclip.copy("你好,剪切板!")
# 从剪切板获取文本
text = pyperclip.paste()
print(f"剪切板内容: {text}")
高级操作(使用 win32clipboard)
pyperclip 只能处理纯文本,如果需要操作图片、文件列表等复杂格式,就需要用到 win32clipboard。
操作 Unicode 文本
import win32clipboard as wcb
import win32con
def set_clipboard_text(text):
"""将文本复制到剪切板"""
wcb.OpenClipboard()
wcb.EmptyClipboard()
wcb.SetClipboardData(win32con.CF_UNICODETEXT, text)
wcb.CloseClipboard()
def get_clipboard_text():
"""从剪切板获取文本"""
wcb.OpenClipboard()
try:
text = wcb.GetClipboardData(win32con.CF_UNICODETEXT)
except:
text = ""
wcb.CloseClipboard()
return text
# 测试
set_clipboard_text("Hello, 剪切板!")
print(get_clipboard_text())
获取剪切板中的所有格式
import win32clipboard as wcb
def list_clipboard_formats():
"""列出剪切板中所有可用的格式"""
wcb.OpenClipboard()
formats = []
fmt = wcb.EnumClipboardFormats(0)
while fmt:
try:
name = wcb.GetClipboardFormatName(fmt)
except:
name = f"标准格式 #{fmt}"
formats.append((fmt, name))
fmt = wcb.EnumClipboardFormats(fmt)
wcb.CloseClipboard()
return formats
# 列出当前剪切板的格式
for fmt_id, fmt_name in list_clipboard_formats():
print(f"格式ID: {fmt_id}, 名称: {fmt_name}")
运行上面的代码,你会发现当你复制不同内容时,剪切板中的格式是不同的:
- 复制纯文本:只有
CF_UNICODETEXT - 复制 Word 内容:会有
CF_UNICODETEXT、Rich Text Format、HTML Format等 - 复制图片:会有
CF_BITMAP、CF_DIB等 - 复制文件:会有
CF_HDROP
复制图片到剪切板
import win32clipboard as wcb
import win32con
from PIL import Image
import io
def copy_image_to_clipboard(image_path):
"""将图片复制到剪切板"""
# 读取图片并转换为 BMP 格式
img = Image.open(image_path)
# 转换为 BMP 格式的字节流
output = io.BytesIO()
img.save(output, 'BMP')
bmp_data = output.getvalue()[14:] # 去掉 BMP 文件头
# 写入剪切板
wcb.OpenClipboard()
wcb.EmptyClipboard()
wcb.SetClipboardData(win32con.CF_DIB, bmp_data)
wcb.CloseClipboard()
# 使用示例
copy_image_to_clipboard("test.png")
从剪切板获取图片
import win32clipboard as wcb
import win32con
from PIL import Image
import io
def get_image_from_clipboard():
"""从剪切板获取图片"""
wcb.OpenClipboard()
try:
# 尝试获取 DIB 格式
data = wcb.GetClipboardData(win32con.CF_DIB)
# 构造 BMP 文件头
bmp_header = b'BM' + (len(data) + 14).to_bytes(4, 'little')
bmp_header += b'\x00\x00\x00\x00' # 保留字段
bmp_header += b'\x36\x00\x00\x00' # 数据偏移
# 组合成完整的 BMP 数据
bmp_data = bmp_header + data
# 用 PIL 打开图片
img = Image.open(io.BytesIO(bmp_data))
return img
except Exception as e:
print(f"获取图片失败: {e}")
return None
finally:
wcb.CloseClipboard()
# 使用示例
img = get_image_from_clipboard()
if img:
img.save("clipboard_image.png")
print("图片已保存")
复制文件列表到剪切板
import win32clipboard as wcb
import win32con
import struct
def copy_files_to_clipboard(file_paths):
"""将文件列表复制到剪切板"""
# 构建 DROPFILES 结构
# DROPFILES 结构:
# DWORD pFiles (文件名偏移量)
# POINT pt (坐标)
# BOOL fNC (是否非客户区)
# BOOL fWide (是否使用 Unicode)
offset = 20 # DROPFILES 结构大小
files_str = '\x00'.join(file_paths) + '\x00\x00'
files_bytes = files_str.encode('utf-16-le')
# 构建完整数据
data = struct.pack('I', offset) # pFiles
data += struct.pack('ii', 0, 0) # pt (x, y)
data += struct.pack('I', 0) # fNC
data += struct.pack('I', 1) # fWide = 1 (Unicode)
data += files_bytes
wcb.OpenClipboard()
wcb.EmptyClipboard()
wcb.SetClipboardData(win32con.CF_HDROP, data)
wcb.CloseClipboard()
# 使用示例
copy_files_to_clipboard([
r"C:\Users\test\file1.txt",
r"C:\Users\test\file2.jpg"
])
print("文件已复制到剪切板")
剪切板的"延迟渲染"机制
你可能会好奇:如果我复制了一个很大的文件,剪切板会不会占用大量内存?
答案是不会,因为 Windows 使用了延迟渲染(Delayed Rendering)机制。
当你复制数据时,数据源应用只是告诉系统"我可以提供这种格式的数据",但并不立即把数据放入剪切板。只有当其他应用请求粘贴时,系统才会通知数据源应用生成数据。
这就是为什么你可以复制一个 1GB 的视频文件,剪切板只存储文件的路径引用,而不是整个视频数据。
实际应用场景
场景一:批量处理剪贴板文本
import pyperclip
import re
def process_clipboard_text():
"""处理剪切板中的文本"""
text = pyperclip.paste()
# 示例:将文本中的所有 URL 转换为 Markdown 链接格式
url_pattern = r'(https?://[^\s]+)'
processed = re.sub(url_pattern, r'[\1](\1)', text)
pyperclip.copy(processed)
print("处理完成!")
process_clipboard_text()
场景二:监控剪切板变化
import win32clipboard as wcb
import win32con
import win32api
import time
def monitor_clipboard(callback, interval=0.5):
"""监控剪切板变化"""
last_sequence = wcb.GetClipboardSequenceNumber()
print("开始监控剪切板...")
try:
while True:
current_sequence = wcb.GetClipboardSequenceNumber()
if current_sequence != last_sequence:
last_sequence = current_sequence
callback()
time.sleep(interval)
except KeyboardInterrupt:
print("\n监控已停止")
def on_clipboard_change():
"""剪切板变化时的回调"""
wcb.OpenClipboard()
try:
text = wcb.GetClipboardData(win32con.CF_UNICODETEXT)
print(f"\n新内容: {text[:50]}..." if len(text) > 50 else f"\n新内容: {text}")
except:
print("\n[非文本内容]")
wcb.CloseClipboard()
# 开始监控
monitor_clipboard(on_clipboard_change)
场景三:多格式粘贴助手
import win32clipboard as wcb
import win32con
class ClipboardHelper:
"""剪切板助手类"""
@staticmethod
def get_all_text_formats():
"""获取所有文本格式的数据"""
wcb.OpenClipboard()
results = {}
text_formats = {
win32con.CF_UNICODETEXT: "Unicode Text",
win32con.CF_TEXT: "ANSI Text",
}
for fmt_id, fmt_name in text_formats.items():
try:
data = wcb.GetClipboardData(fmt_id)
results[fmt_name] = data
except:
pass
# 尝试获取 RTF 和 HTML
try:
rtf_fmt = wcb.RegisterClipboardFormat("Rich Text Format")
results["RTF"] = wcb.GetClipboardData(rtf_fmt)
except:
pass
try:
html_fmt = wcb.RegisterClipboardFormat("HTML Format")
results["HTML"] = wcb.GetClipboardData(html_fmt)
except:
pass
wcb.CloseClipboard()
return results
# 使用示例
formats = ClipboardHelper.get_all_text_formats()
for name, content in formats.items():
preview = str(content)[:100] + "..." if len(str(content)) > 100 else str(content)
print(f"{name}: {preview}")
常见问题与注意事项
1. 剪切板被占用
当其他程序正在使用剪切板时,你的程序可能会失败。解决方法:
import win32clipboard as wcb
import time
def safe_open_clipboard(max_retries=5, delay=0.1):
"""安全地打开剪切板"""
for i in range(max_retries):
try:
wcb.OpenClipboard()
return True
except:
time.sleep(delay)
return False
2. 数据格式转换
不同格式之间可能需要转换。例如,从 HTML 格式提取纯文本:
import re
def html_to_text(html):
"""简单的 HTML 转纯文本"""
text = re.sub(r'<[^>]+>', '', html)
text = re.sub(r' ', ' ', text)
text = re.sub(r'<', '<', text)
text = re.sub(r'>', '>', text)
text = re.sub(r'&', '&', text)
return text.strip()
3. 跨平台兼容性
win32clipboard 只能在 Windows 上使用。如果需要跨平台,可以使用 pyperclip 处理文本,或者使用条件导入:
import sys
if sys.platform == 'win32':
import win32clipboard as wcb
# Windows 特定代码
elif sys.platform == 'darwin':
# macOS 特定代码
pass
else:
# Linux 特定代码
pass
总结
通过这篇文章,我们了解了:
- 剪切板的基本概念:它是应用程序之间数据传递的中转站
- 支持的数据类型:文本、图片、富文本、HTML、文件列表等
- Python 操作方法:
pyperclip:简单易用,适合纯文本操作win32clipboard:功能强大,支持所有格式- 实际应用场景:批量处理、监控变化、多格式转换
剪切板虽然看起来简单,但背后涉及的机制相当复杂。理解这些数据类型和操作方法,能帮助你开发出更强大的自动化工具和应用。
希望这篇文章对你有所帮助!如果你有任何问题或想法,欢迎留言讨论。