Кто-нибудь знает, как мне получить текущие открытые окна или процесс на локальном компьютере с помощью Java?
Я пытаюсь сделать следующее: перечислить текущую открытую задачу, окна или открытые процессы, как в диспетчере задач Windows, но с использованием многоплатформенного подхода - используя только Java, если это возможно.




Единственный способ, которым я могу это сделать, - это вызвать приложение командной строки, которое выполняет эту работу за вас, а затем выполнить сканирование экрана вывода (например, ps в Linux и список задач Windows).
К сожалению, это будет означать, что вам придется написать несколько процедур синтаксического анализа для чтения данных из обоих.
Process proc = Runtime.getRuntime().exec ("tasklist.exe");
InputStream procOutput = proc.getInputStream ();
if (0 == proc.waitFor ()) {
// TODO scan the procOutput for your data
}
В Windows программу tasklist можно настроить для вывода CSV :)
Это еще один подход к синтаксическому анализу списка процессов из команды "ps -e":
try {
String line;
Process p = Runtime.getRuntime().exec("ps -e");
BufferedReader input =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line); //<-- Parse data here.
}
input.close();
} catch (Exception err) {
err.printStackTrace();
}
Если вы используете Windows, вам следует изменить строку: «Process p = Runtime.getRun ...» и т. д. (3-я строка), чтобы она выглядела так:
Process p = Runtime.getRuntime().exec
(System.getenv("windir") +"\system32\"+"tasklist.exe");
Надеюсь, информация поможет!
как получить время начала и окончания процесса
В Windows запустите tasklist.exe /fo csv /nh, чтобы получить список в формате CSV, который намного проще анализировать.
но имя банки не отображается. Имя моего исполняемого файла - helloDemo.jar. но он ничего не показывает
Почему бы не сработать, если я добавлю | grep java? то есть ps -elf | grep java ничего не вернет, но ps -elf будет работать должным образом.
Следует отметить, что бит "специфичный для Windows" внизу кажется ненужным. В Windows 10 (.exec (Runtime/getRuntime) "tasklist")) (в Clojure с использованием Java-interop) правильно возвращает процесс tasklist, даже без указания каталога.
Не существует нейтрального для платформы способа сделать это. В версии Java 1.6 был добавлен класс «Рабочий стол», позволяющий переносить способы просмотра, редактирования, отправки по почте, открытия и печати URI. Возможно, этот класс когда-нибудь будет расширен для поддержки процессов, но я сомневаюсь в этом.
Если вас интересуют только процессы Java, вы можете использовать java.lang.management api для получения информации о потоках / памяти на JVM.
YAJSW (еще один Java Service Wrapper) выглядит так, как будто он имеет основанные на JNA реализации своего интерфейса org.rzo.yajsw.os.TaskList для win32, linux, bsd и solaris и находится под лицензией LGPL. Я не пробовал вызывать этот код напрямую, но YAJSW работает очень хорошо, когда я использовал его в прошлом, так что у вас не должно быть слишком много проблем.
по-видимому, v12 + - это двойная лицензия Apache / LGPL
В Windows есть альтернатива с использованием JNA:
import com.sun.jna.Native;
import com.sun.jna.platform.win32.*;
import com.sun.jna.win32.W32APIOptions;
public class ProcessList {
public static void main(String[] args) {
WinNT winNT = (WinNT) Native.loadLibrary(WinNT.class, W32APIOptions.UNICODE_OPTIONS);
WinNT.HANDLE snapshot = winNT.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new WinDef.DWORD(0));
Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();
while (winNT.Process32Next(snapshot, processEntry)) {
System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile));
}
winNT.CloseHandle(snapshot);
}
}
Это дает только имя команды, а НЕ всю командную строку. Есть ли способ получить всю командную строку?
Вы можете получить полный путь, позвонив в GetModuleFileName. См. Пример stackoverflow.com/questions/7521693/….
Единственная проблема с этим заключается в том, что он дает только путь процесса, а НЕ всю командную строку. Есть ли способ получить полную командную строку процесса (например, ant.bat -f helloWorld.ext)?
как проверить, запущен ли конкретный процесс, например xyz.exe?
@ChristopherDancy не уверен, нужен ли вам ответ, но для полноты и, как здесь не упоминалось: Командная строка информации об управлении Winodws (или просто wmic.exe) предоставляет способ получить много информации о запущенных приложениях - WMIC PROCESS или ограничить вывод для определенного процесса: WMIC PROCESS WHERE name='theName'. При необходимости вы можете использовать дополнительные фильтры, чтобы ограничить вывод. Командная строка включена в столбец CommandLine возвращаемой таблицы (= 2-й столбец)
@PrashantSharma Вы можете проверить WMIC PROCESS WHERE name='nameOfApp', если вторая строка (первая строка - заголовок таблицы) содержит No instance available, нет запущенного процесса с таким именем, иначе вы получите кучу информации о запущенном процессе.
@ChristopherDancy о, забыл упомянуть: вы даже можете извлечь командную строку напрямую, используя WMIC PROCESS WHERE "name like '%nameOfApp%'" get Commandline
Использование кода для синтаксического анализа ps aux для Linux и tasklist для Windows - ваши лучшие варианты, пока не появится что-то более общее.
Для windows вы можете ссылаться на: http://www.rgagnon.com/javadetails/java-0593.html
Linux также может передавать результаты ps aux через grep, что упростит и ускорит обработку / поиск. Я уверен, что вы можете найти что-то подобное и для окон.
Вы также можете посмотреть список задач более подробно: technet.microsoft.com/en-us/library/bb491010.aspx
package com.vipul;
import java.applet.Applet;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class BatchExecuteService extends Applet {
public Choice choice;
public void init()
{
setFont(new Font("Helvetica", Font.BOLD, 36));
choice = new Choice();
}
public static void main(String[] args) {
BatchExecuteService batchExecuteService = new BatchExecuteService();
batchExecuteService.run();
}
List<String> processList = new ArrayList<String>();
public void run() {
try {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("D:\server.bat");
process.getOutputStream().close();
InputStream inputStream = process.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(
inputStream);
BufferedReader bufferedrReader = new BufferedReader(
inputstreamreader);
BufferedReader bufferedrReader1 = new BufferedReader(
inputstreamreader);
String strLine = "";
String x[]=new String[100];
int i=0;
int t=0;
while ((strLine = bufferedrReader.readLine()) != null)
{
// System.out.println(strLine);
String[] a=strLine.split(",");
x[i++]=a[0];
}
// System.out.println("Length : "+i);
for(int j=2;j<i;j++)
{
System.out.println(x[j]);
}
}
catch (IOException ioException)
{
ioException.printStackTrace();
}
}
}
You can create batch file likeTASKLIST /v /FI "STATUS eq running" /FO "CSV" /FI "Username eq LHPL002\soft" /FI "MEMUSAGE gt 10000" /FI "Windowtitle ne N/A" /NH
Вы можете легко получить список запущенных процессов, используя jProcesses
List<ProcessInfo> processesList = JProcesses.getProcessList();
for (final ProcessInfo processInfo : processesList) {
System.out.println("Process PID: " + processInfo.getPid());
System.out.println("Process Name: " + processInfo.getName());
System.out.println("Process Used Time: " + processInfo.getTime());
System.out.println("Full command: " + processInfo.getCommand());
System.out.println("------------------");
}
эта библиотека кажется очень медленной ... есть ли для этого причина (или это общее взаимодействие java + wmi через vbs?
Я думаю, вы говорите о реализации Windows. Да, обычно запросы WMI занимают некоторое время. Как всегда, это зависит от варианта использования. Если вам нужно выполнять запрос каждые 10 мс, да, это слишком медленно.
да, я говорил о победе, в Linux я заметил использование "ps ... <options>", так что я думаю, это должно быть намного быстрее
Хорошо, если вы хотите, вы можете создать проблему в проекте github, и я в конечном итоге посмотрю и посмотрю, смогу ли я улучшить производительность в Win. На самом деле я использовал его в Linux, поэтому не обращал особого внимания на реализацию win: -S
Это нормально, но то, что я искал: в вашем процессе startTime вы ограничили заданное время на один день (чч: мм: сс), если я не ошибаюсь. Есть ли возможность получить также дату + время (гггг-мм-дд-чч: мм: сс)?
Умм, это ненормально. Время начала берется из свойства CreationDate класса WIN32_PROCESS (msdn.microsoft.com/en-us/library/windows/desktop/…), которое обычно выглядит примерно так: 20160418081141.713311 + 120. Пожалуйста, создайте проблему, и я рассмотрю ее. У меня сейчас нет доступа к машине с Windows.
Для окон я использую следующее:
Process process = new ProcessBuilder("tasklist.exe", "/fo", "csv", "/nh").start();
new Thread(() -> {
Scanner sc = new Scanner(process.getInputStream());
if (sc.hasNextLine()) sc.nextLine();
while (sc.hasNextLine()) {
String line = sc.nextLine();
String[] parts = line.split(",");
String unq = parts[0].substring(1).replaceFirst(".$", "");
String pid = parts[1].substring(1).replaceFirst(".$", "");
System.out.println(unq + " " + pid);
}
}).start();
process.waitFor();
System.out.println("Done");
Наконец, с Java 9+ это возможно с ProcessHandle:
public static void main(String[] args) {
ProcessHandle.allProcesses()
.forEach(process -> System.out.println(processDetails(process)));
}
private static String processDetails(ProcessHandle process) {
return String.format("%8d %8s %10s %26s %-40s",
process.pid(),
text(process.parent().map(ProcessHandle::pid)),
text(process.info().user()),
text(process.info().startInstant()),
text(process.info().commandLine()));
}
private static String text(Optional<?> optional) {
return optional.map(Object::toString).orElse("-");
}
Выход:
1 - root 2017-11-19T18:01:13.100Z /sbin/init
...
639 1325 www-data 2018-12-04T06:35:58.680Z /usr/sbin/apache2 -k start
...
23082 11054 huguesm 2018-12-04T10:24:22.100Z /.../java ProcessListDemo
Какой импорт нужно добавить для работы с ProcessHandle?
Этот класс находится в java.lang, поэтому импорт не требуется
Это может быть полезно для приложений со встроенной JRE: я ищу имя папки, из которой я запускаю приложение: поэтому, если ваше приложение выполняется из:
C:\Dev\build\SomeJavaApp\jre-9.0.1\bin\javaw.exe
то вы можете узнать, работает ли он уже в J9, с помощью:
public static void main(String[] args) {
AtomicBoolean isRunning = new AtomicBoolean(false);
ProcessHandle.allProcesses()
.filter(ph -> ph.info().command().isPresent() && ph.info().command().get().contains("SomeJavaApp"))
.forEach((process) -> {
isRunning.set(true);
});
if (isRunning.get()) System.out.println("SomeJavaApp is running already");
}
Это мой код для функции, которая получает задачи и их имена, а также добавляет их в список для доступа из списка. Он создает временные файлы с данными, считывает файлы и получает имя задачи с суффиксом .exe и упорядочивает файлы, которые должны быть удалены при выходе из программы с помощью System.exit (0), а также скрывает процессы, используемые для получить задачи, а также java.exe, чтобы пользователь не мог случайно убить процесс, который запускает программу вместе.
private static final DefaultListModel tasks = new DefaultListModel();
public static void getTasks()
{
new Thread()
{
@Override
public void run()
{
try
{
File batchFile = File.createTempFile("batchFile", ".bat");
File logFile = File.createTempFile("log", ".txt");
String logFilePath = logFile.getAbsolutePath();
try (PrintWriter fileCreator = new PrintWriter(batchFile))
{
String[] linesToPrint = {"@echo off", "tasklist.exe >>" + logFilePath, "exit"};
for(String string:linesToPrint)
{
fileCreator.println(string);
}
fileCreator.close();
}
int task = Runtime.getRuntime().exec(batchFile.getAbsolutePath()).waitFor();
if (task == 0)
{
FileReader fileOpener = new FileReader(logFile);
try (BufferedReader reader = new BufferedReader(fileOpener))
{
String line;
while(true)
{
line = reader.readLine();
if (line != null)
{
if (line.endsWith("K"))
{
if (line.contains(".exe"))
{
int index = line.lastIndexOf(".exe", line.length());
String taskName = line.substring(0, index + 4);
if (! taskName.equals("tasklist.exe") && ! taskName.equals("cmd.exe") && ! taskName.equals("java.exe"))
{
tasks.addElement(taskName);
}
}
}
}
else
{
reader.close();
break;
}
}
}
}
batchFile.deleteOnExit();
logFile.deleteOnExit();
}
catch (FileNotFoundException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IOException | InterruptedException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
catch (NullPointerException ex)
{
// This stops errors from being thrown on an empty line
}
}
}.start();
}
public static void killTask(String taskName)
{
new Thread()
{
@Override
public void run()
{
try
{
Runtime.getRuntime().exec("taskkill.exe /IM " + taskName);
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
}
}.start();
}
Я также превратил этот код в полноценную программу, чтобы попытаться воспроизвести встроенный диспетчер задач для Windows 10. Если кому-то интересно, я могу отправить вам его демонстрацию.
Приведенная ниже программа будет совместима только с версией Java 9+ ...
Чтобы получить информацию о CurrentProcess,
public class CurrentProcess {
public static void main(String[] args) {
ProcessHandle handle = ProcessHandle.current();
System.out.println("Current Running Process Id: "+handle.pid());
ProcessHandle.Info info = handle.info();
System.out.println("ProcessHandle.Info : "+info);
}
}
Для всех запущенных процессов
import java.util.List;
import java.util.stream.Collectors;
public class AllProcesses {
public static void main(String[] args) {
ProcessHandle.allProcesses().forEach(processHandle -> {
System.out.println(processHandle.pid()+" "+processHandle.info());
});
}
}
String line;
Process process = Runtime.getRuntime().exec("ps -e");
process.getOutputStream().close();
BufferedReader input =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line); //<-- Parse data here.
}
input.close();Мы должны использовать process.getOutputStream.close(), иначе он будет заблокирован в цикле while.
Да, я уже думал об этом, но мне кажется, что это можно сделать только с Java. И я думаю, что лучше было бы использовать «ps -aux» вместо top. Спасибо за быстрый ответ!