1 概述
本文主要讲述了如何利用xsel 在Linux 环境下对系统剪贴板的访问。
2 起因
在搜索引擎直接搜索“Java 访问剪贴板”,大部分都是直接使用AWT API 进行访问的例子:
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection selection = new StringSelection("test");
clipboard.setContents(selection, selection);
但是,一个最大的问题是,需要该程序一直运行,才能访问到剪贴板,因此,如果没有其他处理逻辑,需要加上线程休眠代码:
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection selection = new StringSelection("test");
clipboard.setContents(selection, selection);
TimeUnit.HOURS.sleep(1);
换句话说,这样只是临时复制到剪贴板,并没有永久复制,那么,有没有其他办法可以在运行程序结束之后也能访问到剪贴板呢?
3 xsel
xsel 是Linux 下访问剪贴板的命令行工具,类似的还有xclip ,没有安装的可以使用包管理器安装。其中写入到剪贴板命令如下:
echo "test clipboard" | xsel -ib
由此想到了可以尝试使用Runtime :
public static void main(String[] args) throws Exception {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("echo \"111\" | xsel -ib");
process.waitFor();
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
for (String s; ((s = reader.readLine()) != null); ) {
builder.append(s);
}
System.out.println(builder);
builder = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
for (String s; ((s = reader.readLine()) != null); ) {
builder.append(s);
}
System.out.println(builder);
int exitValue = process.exitValue();
System.out.println("exitValue is " + exitValue);
if (exitValue != 0) {
System.out.println("error");
}
process.destroy();
}
运行之后输出如下:
"111" | xsel -ib
"111" | xsel -ib
exitValue is 0
可以看到输出结果是不正常的,这样就相当于变成了执行
echo "\"111\" | xsel -ib"
也就是输出的字符串都是echo 的参数。
4 创建脚本文件
出现上面结果的原因是Process 并不能直接支持使用管道运算符,因此,采用直接创建脚本运行命令的方法。
步骤:
- 创建临时脚本文件:使用
Files.createFile 创建 - 授权:
700 权限,也就是所有者读、写、执行权限,使用Files.setPosixFilePermissions - 写入脚本文件:向脚本文件写入
echo str | xsel -ib ,使用Files.writeString - 执行:利用
Process.exec 执行脚本文件 - 删除:利用
Files.delete 删除临时文件
代码如下:
public static void main(String[] args) throws Exception {
String fileName = "1.sh";
Path executeFile = Files.createFile(Path.of(fileName));
Files.setPosixFilePermissions(executeFile, Set.of(PosixFilePermission.OWNER_WRITE,
PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_READ));
String clipboardContent = "111";
Files.writeString(executeFile, "echo " + clipboardContent + " | xsel -ib");
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("./" + fileName);
process.waitFor();
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
for (String s; ((s = reader.readLine()) != null); ) {
builder.append(s);
}
System.out.println(builder);
builder = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
for (String s; ((s = reader.readLine()) != null); ) {
builder.append(s);
}
System.out.println(builder);
int exitValue = process.exitValue();
System.out.println("exitValue is " + exitValue);
if (exitValue != 0) {
System.out.println("error");
}
Files.delete(executeFile);
process.destroy();
}
输出:
exitValue is 0
有两行空行是System.out.println() 的换行输出,说明Process 的inputStream 以及errorStream 都没有内容。
测试结果也是正常,能够剪贴出111 字符串。
5 从剪贴板读取
从剪贴板读取的原理类似,就是xsel 的参数不一样,这里不展开了,放上完整代码:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
public class Main {
private static final String FILENAME = "1.sh";
public static void main(String[] args) throws Exception {
writeToClipboard("111111");
System.out.println(readFromClipboard());
writeToClipboard("22222");
System.out.println(readFromClipboard());
}
private static void writeToClipboard(String content) throws Exception {
Path executeFile = createFile("echo " + content + " | xsel -ib");
exec(executeFile);
}
private static String readFromClipboard() throws Exception {
Path executeFile = createFile("xsel -ob");
return exec(executeFile);
}
private static Path createFile(String fileContent) throws Exception {
Path executeFile = Files.createFile(Path.of(FILENAME));
Files.setPosixFilePermissions(executeFile, Set.of(PosixFilePermission.OWNER_WRITE,
PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_READ));
Files.writeString(executeFile, fileContent);
return executeFile;
}
private static String exec(Path executeFile) throws Exception {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("./" + FILENAME);
process.waitFor();
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
for (String s; ((s = reader.readLine()) != null); ) {
builder.append(s);
}
String res = "";
if (builder.length() != 0) {
res = builder.toString();
}
reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
builder = new StringBuilder();
for (String s; ((s = reader.readLine()) != null); ) {
builder.append(s);
}
if (builder.length() != 0) {
System.out.println(builder);
}
int exitValue = process.exitValue();
System.out.println("exitValue is " + exitValue);
if (exitValue != 0) {
System.out.println("error");
}
Files.delete(executeFile);
process.destroy();
return res;
}
}
|