Como obter uma lista de janelas / processos abertos no momento com o Java?

94

Alguém sabe como faço para obter as janelas atuais abertas ou o processo de uma máquina local usando Java?

O que estou tentando fazer é: listar a tarefa, janelas ou processos abertos no momento, como no gerenciador de tarefas do Windows, mas usando uma abordagem multiplataforma - usando apenas Java se possível.

ramayac
fonte

Respostas:

104

Esta é outra abordagem para analisar a lista de processos a partir do 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 você estiver usando o Windows, deve alterar a linha: "Process p = Runtime.getRun ..." etc ... (3ª linha), por uma que se pareça com isto:

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

Espero que as informações ajudem!

ramayac
fonte
como obter a hora de início e de término do processo
Bucks
34
No Windows, execute tasklist.exe /fo csv /nhpara obter a lista no formato CSV, que é muito mais fácil de analisar.
Emmanuel Bourg
mas não está mostrando o nome do jar. Meu nome de jar executável é helloDemo.jar. mas não está mostrando nada a favor
Sumon Bappi
Por que não funcionaria se eu adicionasse um | grep java? ou seja ps -elf | grep java, não retornará nada, mas ps -elffuncionará conforme o esperado.
Itay Moav -Malimovka
Deve-se notar que o bit "específico para janelas" na parte inferior parece ser desnecessário. No Windows 10, (.exec (Runtime/getRuntime) "tasklist"))(em Clojure, usando Java-interop) retorna corretamente o tasklistprocesso, mesmo sem especificar um diretório.
Carcigenicar-se em
39

Finalmente, com Java 9+ é possível com 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("-");
}

Resultado:

    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.
fonte
Quais importações devem ser adicionadas para trabalhar com ProcessHandle?
Jordi
2
Essa classe está em java.langtão nenhuma importação necessária
Hugues M.
23

No Windows, há uma alternativa para usar 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
fonte
Isso fornece apenas o nome do comando, NÃO toda a linha de comando. Existe uma maneira de obter toda a linha de comando?
Christopher Dancy
2
Você pode obter o caminho completo chamando GetModuleFileName. Consulte stackoverflow.com/questions/7521693/… para obter um exemplo.
Emmanuel Bourg
O único problema com isso é que ele fornece apenas o caminho do processo, NÃO a linha de comando inteira. Existe uma maneira de obter a linha de comando completa do processo (ou seja, 'ant.bat -f helloWorld.ext')?
Christopher Dancy
como verificar se um processo específico como xyz.exe está em execução ou não?
unknownbits
@ChristopherDancy não tem certeza se você ainda precisa de uma resposta, mas para estar completo e como não foi mencionado aqui: Winodws Managment Information Command-line (ou simplesmente wmic.exe) fornece uma maneira de recuperar muitas informações de aplicativos em execução - WMIC PROCESSou para restringir a saída para um processo específico: WMIC PROCESS WHERE name='theName'. Você pode usar outros filtros para limitar a saída, se necessário. A linha de comando está incluída na coluna CommandLine da tabela retornada (= 2ª coluna)
Roman Vottner
9

A única maneira que consigo pensar em fazer isso é invocando um aplicativo de linha de comando que faz o trabalho para você e, em seguida, capturando a tela da saída (como o ps do Linux e a lista de tarefas do Windows).

Infelizmente, isso significa que você terá que escrever algumas rotinas de análise para ler os dados de ambos.

Process proc = Runtime.getRuntime().exec ("tasklist.exe");
InputStream procOutput = proc.getInputStream ();
if (0 == proc.waitFor ()) {
    // TODO scan the procOutput for your data
}
Jodonnell
fonte
1
Sim, eu já pensei sobre isso também, mas acho que poderia ser feito apenas com Java. E eu acho que seria melhor usar "ps -aux" em vez de top. Obrigado pela resposta rápida!
ramayac
No Windows, o tasklistprograma pode ser configurado para produzir CSV :)
MauganRa
7

YAJSW (Yet Another Java Service Wrapper) parece ter implementações baseadas em JNA de sua interface org.rzo.yajsw.os.TaskList para win32, linux, bsd e solaris e está sob uma licença LGPL. Não tentei chamar este código diretamente, mas YAJSW funciona muito bem quando eu o usei no passado, então você não deve se preocupar muito.

SamWest
fonte
aparentemente v12 + é uma licença dupla Apache / LGPL
harschware
5

Você pode facilmente recuperar a lista de processos em execução usando 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
fonte
esta biblioteca parece ser muito lenta ... há uma razão para isso (ou é a interoperabilidade java + wmi geral entre vbs?
Gobliins
2
Eu acho que você fala sobre a implementação do Windows. Sim, normalmente as consultas WMI demoram algum tempo. Como sempre, depende do caso de uso. Se precisar realizar a consulta a cada 10 ms, sim, é muito lento.
profesor_falken
sim, eu estava falando sobre win, no linux eu descobri o uso de "ps ... <options>" então eu acho que deveria ser muito mais rápido
Gobliins
Ok, se você quiser, pode criar um problema no projeto github e irei eventualmente dar uma olhada e ver se posso melhorar o desempenho no Win. Na verdade, eu usei no Linux, então não prestei muita atenção na implementação do Win: -S
profesor_falken
Tudo bem, mas o que eu estava procurando: Em seu processo startTime você limitou o tempo dado por um dia (hh: mm: ss) se eu não estiver errado. Existe alguma opção de obter também a data + hora (aaaa-mm-dd-hh: mm: ss)?
Gobliins de
4

Não existe uma maneira neutra de plataforma de fazer isso. Na versão 1.6 do Java, uma classe " Desktop " foi adicionada para permitir maneiras portáteis de navegar, editar, enviar, abrir e imprimir URIs. É possível que algum dia essa classe seja estendida para apoiar processos, mas eu duvido.

Se você estiver apenas curioso em processos Java, pode usar a api java.lang.management para obter informações de thread / memória na JVM.

Hazzen
fonte
4

Para windows eu uso o seguinte:

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
fonte
4

Isso pode ser útil para aplicativos com um JRE incluído: eu procuro o nome da pasta da qual estou executando o aplicativo: portanto, se o seu aplicativo estiver sendo executado:

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

então você pode descobrir se ele já está em execução no 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");
}
cera
fonte
3

Usar código para analisar ps auxpara Linux e tasklistWindows são suas melhores opções, até que algo mais geral apareça.

Para Windows, você pode consultar: http://www.rgagnon.com/javadetails/java-0593.html

Linux pode canalizar os resultados do ps auxmeio greptambém, o que tornaria o processamento / busca rápida e fácil. Tenho certeza que você pode encontrar algo semelhante para o Windows também.

James Oravec
fonte
Você também pode querer dar uma olhada na lista de tarefas com mais detalhes: technet.microsoft.com/en-us/library/bb491010.aspx
James Oravec
2

O programa abaixo será compatível apenas com a versão Java 9+ ...

Para obter as informações do 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);
    }
}

Para todos os processos em execução,

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

Temos que usar, process.getOutputStream.close()caso contrário, ele ficará travado no loop while.

Jijo Joy
fonte
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 executando" / FO "CSV" / FI "Nome de usuário eq LHPL002 \ soft" / FI "MEMUSAGE gt 10000" / FI "Windowtitle ne N / A" / NH

Panchotiya Vipul
fonte
0

Este é meu código para uma função que obtém as tarefas e seus nomes, adicionando-as também a uma lista para ser acessada de uma lista. Ele cria arquivos temporários com os dados, lê os arquivos e obtém o nome da tarefa com o sufixo .exe e organiza os arquivos a serem excluídos quando o programa sai com System.exit (0), também oculta os processos que estão sendo usados ​​para obtenha as tarefas e também o java.exe para que o usuário não elimine acidentalmente o processo que executa o programa.

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
fonte
Também transformei esse código em um programa completo para tentar replicar o gerenciador de tarefas integrado do Windows 10; se alguém estiver interessado, posso enviar uma demonstração dele.
Dylan Wedman