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;
}
}