Come ottenere un elenco delle finestre / processi aperti correnti con Java?


94

Qualcuno sa come ottengo le finestre aperte correnti o il processo di una macchina locale utilizzando Java?

Quello che sto cercando di fare è: elenca l'attività aperta corrente, le finestre o il processo aperto, come in Taskmanager di Windows, ma utilizzando un approccio multipiattaforma, utilizzando solo Java, se possibile.

Risposte:


104

Questo è un altro approccio per analizzare l'elenco dei processi dal comando " 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();
}

Se stai usando Windows, dovresti cambiare la riga: "Process p = Runtime.getRun ..." ecc ... (3a riga), per uno che assomigli a questo:

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

Spero che le informazioni siano d'aiuto!


come ottenere l'ora di inizio e l'ora di fine del processo
Bucks

34
Su Windows, esegui tasklist.exe /fo csv /nhper ottenere l'elenco in formato CSV, che è molto più facile da analizzare.
Emmanuel Bourg

ma non mostra il nome del barattolo. Il nome del mio jar eseguibile è helloDemo.jar. ma non mostra nulla per esso
Sumon Bappi

Perché non funzionerebbe se aggiungo un | grep java? cioè ps -elf | grep javanon restituirà nulla, ma ps -elffunzionerà come previsto.
Itay Moav -Malimovka

Va notato che il bit "specifico per Windows" in basso sembra non essere necessario. Su Windows 10, (.exec (Runtime/getRuntime) "tasklist"))(in Clojure, utilizzando Java-interop) restituisce correttamente il tasklistprocesso, anche senza specificare una directory.
Carcigenicate

39

Infine, con Java 9+ è possibile con 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("-");
}

Produzione:

    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

Quali importazioni dovrebbero essere aggiunte per lavorare con ProcessHandle?
Jordi

2
Quella lezione non è java.langquindi necessaria
Hugues M.

23

Su Windows esiste un'alternativa che utilizza 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);
    }
}

Questo fornisce solo il nome del comando NON l'intera riga di comando. C'è un modo per ottenere l'intera riga di comando?
Christopher Dancy

2
Puoi ottenere il percorso completo chiamando GetModuleFileName. Vedi stackoverflow.com/questions/7521693/… per un esempio.
Emmanuel Bourg

L'unico problema con questo è che fornisce solo il percorso del processo NON l'intera riga di comando. C'è un modo per ottenere la riga di comando completa del processo (ad esempio 'ant.bat -f helloWorld.ext')?
Christopher Dancy

come verificare la presenza di un particolare processo come xyz.exe è in esecuzione o no?
unknownbits

@ChristopherDancy non è sicuro se hai ancora bisogno di una risposta ma per completezza e poiché non è stato menzionato qui: Winodws Managment Information Command-line (o semplicemente wmic.exe) fornisce un modo per recuperare molte informazioni sulle applicazioni in esecuzione - WMIC PROCESSo per limitare l'output per un processo specifico: WMIC PROCESS WHERE name='theName'. È possibile utilizzare ulteriori filtri per limitare l'output, se necessario. La riga di comando è inclusa nella colonna CommandLine della tabella restituita (= 2a colonna)
Roman Vottner

9

L'unico modo in cui posso pensare di farlo è invocare un'applicazione a riga di comando che fa il lavoro per te e quindi fare lo screenshot dell'output (come ps di Linux e tasklist di Windows).

Sfortunatamente, ciò significa che dovrai scrivere alcune routine di analisi per leggere i dati da entrambi.

Process proc = Runtime.getRuntime().exec ("tasklist.exe");
InputStream procOutput = proc.getInputStream ();
if (0 == proc.waitFor ()) {
    // TODO scan the procOutput for your data
}

1
Sì, ho già pensato anche a questo, ma sono duro che potrebbe essere fatto solo con Java. E penso che sarebbe meglio usare "ps -aux" invece di top. Grazie per la risposta rapida!
Ramayac

Su Windows, il tasklistprogramma può essere configurato per l'output CSV :)
MauganRa

7

YAJSW (Yet Another Java Service Wrapper) sembra che abbia implementazioni basate su JNA della sua interfaccia org.rzo.yajsw.os.TaskList per win32, linux, bsd e solaris ed è sotto una licenza LGPL. Non ho provato a chiamare direttamente questo codice, ma YAJSW funziona molto bene quando l'ho usato in passato, quindi non dovresti avere troppe preoccupazioni.


apparentemente v12 + è una doppia licenza Apache / LGPL
harschware

5

Puoi facilmente recuperare l'elenco dei processi in esecuzione utilizzando 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("------------------");
}

questa libreria sembra essere molto lenta ... c'è una ragione per questo (o è l'interoperabilità generale java + wmi su vbs?
Gobliins

2
Immagino tu parli dell'implementazione di Windows. Sì, normalmente le query WMI richiedono del tempo. Come sempre dipende dal caso d'uso. Se è necessario eseguire la query ogni 10 ms, sì, è troppo lenta.
profesor_falken

sì, stavo parlando di vittoria, in Linux ho notato l'uso di "ps ... <opzioni>" quindi immagino che dovrebbe essere molto più veloce
Gobliins

Ok, se vuoi puoi creare un problema nel progetto GitHub e alla fine darò un'occhiata e vedrò se posso migliorare le prestazioni in Win. Infatti l'ho usato su Linux quindi non ho prestato molta attenzione a vincere l'implementazione: -S
profesor_falken

Va bene, ma quello che stavo cercando: Nel tuo processo startTime hai limitato il tempo dato per un giorno (hh: mm: ss) se non sbaglio. C'è qualche opzione per ottenere anche la data e l'ora (aaaa-mm-gg-hh: mm: ss)?
Gobliins

4

Non esiste un modo neutrale per la piattaforma per farlo. Nella versione 1.6 di Java, è stata aggiunta una classe " Desktop " che consente modalità portabili di navigazione, modifica, invio di posta, apertura e stampa di URI. È possibile che un giorno questa classe possa essere estesa per supportare i processi, ma ne dubito.

Se sei curioso solo dei processi Java, puoi utilizzare l' API java.lang.management per ottenere informazioni su thread / memoria sulla JVM.


4

Per Windows utilizzo quanto segue:

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

4

Questo potrebbe essere utile per le app con un JRE in bundle: cerco il nome della cartella da cui sto eseguendo l'applicazione: quindi se la tua applicazione è in esecuzione da:

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

quindi puoi scoprire se è già in esecuzione in J9, da:

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

3

Usare il codice per analizzare ps auxper Linux e tasklistper Windows è la scelta migliore, finché non arriva qualcosa di più generale.

Per Windows, puoi fare riferimento a: http://www.rgagnon.com/javadetails/java-0593.html

Lattina tubo di Linux i risultati di ps auxattraverso greptroppo, il che renderebbe l'elaborazione / ricerca semplice e veloce. Sono sicuro che puoi trovare qualcosa di simile anche per Windows.


Puoi anche esaminare l'elenco delle attività in modo più dettagliato: technet.microsoft.com/en-us/library/bb491010.aspx
James Oravec

2

Il programma seguente sarà compatibile solo con la versione Java 9+ ...

Per ottenere le informazioni su 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);
    }
}

Per tutti i processi in esecuzione,

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

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

Dobbiamo usare process.getOutputStream.close()altrimenti verrà bloccato nel ciclo while.


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


0

Questo è il mio codice per una funzione che ottiene le attività e ottiene i loro nomi, aggiungendole anche a un elenco a cui accedere da un elenco. Crea file temporanei con i dati, legge i file e ottiene il nome dell'attività con il suffisso .exe e dispone i file da eliminare quando il programma è uscito con System.exit (0), nasconde anche i processi utilizzati per ottenere le attività e anche java.exe in modo che l'utente non possa uccidere accidentalmente il processo che esegue il programma tutti insieme.

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

Ho anche trasformato questo codice in un programma completo per provare a replicare il task manager integrato per Windows 10, se qualcuno è interessato, posso inviarti una demo.
Dylan Wedman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.