Jak uzyskać listę aktualnie otwartych okien / procesów w Javie?

95

Czy ktoś wie, jak uzyskać aktualne otwarte okna lub proces na komputerze lokalnym przy użyciu języka Java?

To, co próbuję zrobić, to: wymienić bieżące otwarte zadania, otwarte okna lub proces, jak w Windows Taskmanager, ale używając podejścia wieloplatformowego - używając tylko Javy, jeśli to możliwe.

ramayac
źródło

Odpowiedzi:

106

To jest inny sposób parsowania listy procesów z polecenia " 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();
}

Jeśli korzystasz z systemu Windows, powinieneś zmienić wiersz: „Process p = Runtime.getRun ...” etc ... (3rd line), na taki, który wygląda tak:

Process p = Runtime.getRuntime().exec
    (System.getenv("windir") +"\\system32\\"+"tasklist.exe");

Mam nadzieję, że te informacje pomogą!

ramayac
źródło
jak uzyskać czas rozpoczęcia i zakończenia procesu
Bucks,
34
W systemie Windows uruchom, tasklist.exe /fo csv /nhaby uzyskać listę w formacie CSV, co jest znacznie łatwiejsze do przeanalizowania.
Emmanuel Bourg
ale nie pokazuje nazwy słoika. Nazwa mojego pliku wykonywalnego jar to helloDemo.jar. ale nic to nie pokazuje
Sumon Bappi
Dlaczego to nie zadziała, gdybym dodał | grep java? ie ps -elf | grep javanie zwróci niczego, ale ps -elfbędzie działać zgodnie z oczekiwaniami.
Itay Moav -Malimovka
Należy zauważyć, że bit „specyficzny dla systemu Windows” na dole wydaje się niepotrzebny. W systemie Windows 10 (.exec (Runtime/getRuntime) "tasklist"))(w Clojure, przy użyciu Java-Interop) poprawnie zwraca tasklistproces, nawet bez określania katalogu.
Carcigenicate
40

Wreszcie z Javą 9+ jest to możliwe dzięki 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("-");
}

Wynik:

    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
Hugues M.
źródło
Które importy należy dodać, aby działały z ProcessHandle?
Jordi
2
Ta klasa jest w trakcie, java.langwięc nie ma potrzeby importowania
Hugues M.
23

W systemie Windows istnieje alternatywa korzystania z 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);
    }
}
Emmanuel Bourg
źródło
To daje tylko nazwę polecenia, a NIE całą linię poleceń. Czy istnieje sposób, aby uzyskać całą linię poleceń?
Christopher Dancy
2
Możesz uzyskać pełną ścieżkę, dzwoniąc GetModuleFileName. Przykład można znaleźć na stackoverflow.com/questions/7521693/… .
Emmanuel Bourg
Jedynym problemem jest to, że podaje tylko ścieżkę procesu, a NIE całą linię poleceń. Czy istnieje sposób, aby uzyskać pełną linię poleceń procesu (np. „Ant.bat -f helloWorld.ext”)?
Christopher Dancy
jak sprawdzić, czy dany proces, taki jak xyz.exe, jest uruchomiony, czy nie?
unknownbits
@ChristopherDancy nie jestem pewien, czy nadal potrzebujesz odpowiedzi, ale ze względu na kompletność i ponieważ nie zostało to tutaj wymienione: Wiersz poleceń Winodws Managment Information (lub po prostu wmic.exe) zapewnia sposób na pobranie dużej ilości informacji o uruchomionych aplikacjach - WMIC PROCESSlub ograniczyć wyjściowe dla procesu parametry: WMIC PROCESS WHERE name='theName'. W razie potrzeby możesz użyć dalszych filtrów, aby ograniczyć wyjście. Wiersz poleceń znajduje się w kolumnie CommandLine w zwróconej tabeli (= druga kolumna)
Roman Vottner
9

Jedynym sposobem, w jaki mogę to zrobić, jest wywołanie aplikacji wiersza poleceń, która wykonuje zadanie za Ciebie, a następnie zeskanowanie danych wyjściowych (jak ps Linux i lista zadań Windows).

Niestety, będzie to oznaczać, że będziesz musiał napisać kilka procedur parsujących, aby odczytać dane z obu.

Process proc = Runtime.getRuntime().exec ("tasklist.exe");
InputStream procOutput = proc.getInputStream ();
if (0 == proc.waitFor ()) {
    // TODO scan the procOutput for your data
}
jodonnell
źródło
1
Tak, już o tym myślałem, ale wydaje mi się, że można to zrobić tylko z Javą. Myślę, że lepiej byłoby użyć "ps -aux" zamiast top. Dzięki za szybką odpowiedź!
ramayac
W systemie Windows tasklistprogram można skonfigurować tak, aby wyświetlał CSV :)
MauganRa
7

YAJSW (Yet Another Java Service Wrapper) wygląda tak, jakby miał oparte na JNA implementacje swojego interfejsu org.rzo.yajsw.os.TaskList dla win32, linux, bsd i solaris i jest na licencji LGPL. Nie próbowałem wywoływać tego kodu bezpośrednio, ale YAJSW działa naprawdę dobrze, gdy używałem go w przeszłości, więc nie powinieneś mieć zbyt wielu zmartwień.

SamWest
źródło
najwyraźniej v12 + to podwójna licencja Apache / LGPL
harschware
5

Możesz łatwo pobrać listę uruchomionych procesów za pomocą 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("------------------");
}
profesor_falken
źródło
Biblioteka ta wydaje się być bardzo powolne ... czy jest to powód do tego (czy jest to ogólnie java + wmi współdziałanie całej VBS?
Gobliins
2
Chyba mówisz o implementacji okien. Tak, zwykle zapytania WMI zajmują trochę czasu. Jak zawsze zależy to od przypadku użycia. Jeśli musisz wykonywać zapytanie co 10 ms, tak, jest zbyt wolne.
profesor_falken
tak, mówiłem o wygranej, w Linuksie zauważyłem użycie "ps ... <options>", więc myślę, że powinno być znacznie szybciej
Gobliins
Ok, jeśli chcesz, możesz utworzyć problem w projekcie na githubie, a ja ostatecznie przyjrzę się temu i zobaczę, czy mogę poprawić wydajność w Win. Właściwie użyłem go na Linuksie, więc nie zwróciłem uwagi na wygraną implementację: -S
profesor_falken
Jest dobrze, ale to, czego szukałem: W swoim procesie startTime ograniczyłeś podany czas na jeden dzień (gg: mm: ss), jeśli się nie mylę. Czy jest jakaś opcja, aby uzyskać również datę i godzinę (rrrr-mm-dd-gg: mm: ss)?
Gobliins
4

Nie ma na to sposobu neutralnego dla platformy. W wersji 1.6 języka Java dodano klasę „ Desktop ”, która umożliwia przenośne sposoby przeglądania, edycji, wysyłania pocztą, otwierania i drukowania identyfikatorów URI. Jest możliwe, że kiedyś ta klasa zostanie rozszerzona o obsługę procesów, ale wątpię w to.

Jeśli interesują Cię tylko procesy w języku Java, możesz użyć interfejsu API java.lang.management, aby uzyskać informacje o wątkach / pamięci w JVM.

hazzen
źródło
4

W przypadku okien używam następujących:

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");
Stepan Yakovenko
źródło
4

Może to być przydatne w przypadku aplikacji z dołączonym środowiskiem JRE: szukam nazwy folderu, z którego uruchamiam aplikację: więc jeśli aplikacja jest wykonywana z:

C:\Dev\build\SomeJavaApp\jre-9.0.1\bin\javaw.exe

możesz sprawdzić, czy działa już w J9, wykonując:

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");
}
wosk_lyryczny
źródło
3

Używanie kodu do analizowania ps auxdla systemu Linux i tasklistdla systemu Windows to najlepsze opcje, dopóki nie pojawi się coś bardziej ogólnego.

W przypadku systemu Windows możesz odwołać się do: http://www.rgagnon.com/javadetails/java-0593.html

Linux może rura wyniki ps auxpoprzez grepzbyt, które sprawiają, przetwarzanie / wyszukiwanie szybkie i łatwe. Jestem pewien, że możesz znaleźć coś podobnego do okien.

James Oravec
źródło
Możesz również spojrzeć na listę zadań
James Oravec
2

Poniższy program będzie kompatybilny tylko z wersją Java 9+ ...

Aby uzyskać informacje o 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);
    }
}

Dla wszystkich uruchomionych procesów

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());
        });
    }
}
Nallamachu
źródło
2

    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();

Musimy użyć, w process.getOutputStream.close()przeciwnym razie zostanie zablokowana pętla while.

Jijo Joy
źródło
0
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 like 

TASKLIST / v / FI "STATUS eq running" / FO "CSV" / FI "Username eq LHPL002 \ soft" / FI "MEMUSAGE gt 10000" / FI "Windowtitle ne N / A" / NH

Panchotiya Vipul
źródło
0

To jest mój kod funkcji, która pobiera zadania i pobiera ich nazwy, a także dodaje je do listy, aby uzyskać dostęp z listy. Tworzy pliki tymczasowe z danymi, odczytuje pliki i pobiera nazwę zadania z przyrostkiem .exe i ustawia pliki do usunięcia po zakończeniu programu za pomocą System.exit (0), ukrywa również procesy, które są używane do pobierz zadania, a także java.exe, aby użytkownik nie mógł przypadkowo zabić procesu, który uruchamia program razem.

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();
}
Dylan Wedman
źródło
Przekształciłem również ten kod w pełny program, aby spróbować replikować wbudowany menedżer zadań dla systemu Windows 10, jeśli ktoś jest zainteresowany, mogę wysłać Ci jego wersję demonstracyjną.
Dylan Wedman