2012-11-12 17 views
7

This post विंडोज के तहत चल रही प्रक्रियाओं की सूची को पुनर्प्राप्त करने का समाधान देता है। संक्षेप में यह करता है:एक कर्सेट-सुरक्षित तरीके से विंडोज़ पर प्रक्रियाओं की सूची प्राप्त करें

String cmd = System.getenv("windir") + "\\system32\\" + "tasklist.exe"; 
Process p = Runtime.getRuntime().exec(cmd); 
InputStreamReader isr = new InputStreamReader(p.getInputStream()); 
BufferedReader input = new BufferedReader(isr); 

तब इनपुट पढ़ता है।

ऐसा लगता है और अच्छा काम करता है, लेकिन अगर वहाँ एक संभावना है कि कार्यसूची द्वारा प्रयोग किया जाता चारसेट डिफ़ॉल्ट चारसेट और इस कॉल विफल हो सकता है कि नहीं हो सकता है मैं सोच रहा था?

उदाहरण this other question about a different executable के लिए पता चलता है कि यह कुछ समस्याओं का कारण बन सकता है।

यदि ऐसा है, तो यह निर्धारित करने का कोई तरीका है कि उचित वर्णमाला क्या होगी? Process और ProcessBuilder:

+0

क्या कोई प्रश्न है? क्या आपने इसे आजमाया और देखा? –

+0

@JimGarrison मुझे InputStreamReader में * "डिफ़ॉल्ट एन्कोडिंग पर निर्भरता" * के बारे में FindBugs से एक चेतावनी मिली है और मुझे कोई जानकारी नहीं है कि इससे कोई समस्या हो सकती है या नहीं। तो मैंने दूसरी पोस्ट की खोज की और पाया कि ऐसा लगता है कि यह हो सकता है। मैं यही जांचना चाहता हूं। मेरी मशीन पर कोड ठीक काम करता है। – assylias

+0

मैं इसे एक प्रश्न के बजाय टिप्पणी के रूप में जोड़ूंगा क्योंकि मेरी अनिश्चितता काफी बड़ी है। उस ने कहा, मुझे लगता है कि एक सिस्टम उपयोगिता द्वारा उपयोग किया जाने वाला चरित्र सेट ओएस स्थापना के लिए डिफ़ॉल्ट लोकेल का होगा। उस लोकेल के लिए पूछताछ और आउटपुट स्ट्रीम की व्याख्या करने के लिए इसका उपयोग करना सबसे सामान्य दृष्टिकोण प्रतीत होता है। लेकिन यदि स्थानीयकरण भी मौजूद हैं, तो आपको उन क्षेत्रों को रिवर्स-इंजीनियरिंग करना होगा जो उन्हें बदल सकते हैं ताकि उन्हें बाहर निकाला जा सके। और यह सब इस बात पर निर्भर है कि सवाल में उपयोगिता को इस तरह अलग-अलग तरीके से बदलने के लिए लिखा गया था या नहीं। – eh9

उत्तर

11

2 भागों में इस तोड़ सकता है:

  1. खिड़कियों हिस्सा
    जावा से आप एक Windows कमांड को क्रियान्वित कर रहे हैं - बाहर से "विंडोज भूमि" में JVM करने के लिए।जब जावा रनटाइम क्लास विंडोज कमांड निष्पादित करता है, तो यह कंसोल & के लिए डीएलएल का उपयोग करता है, इसलिए विंडोज़ में प्रतीत होता है जैसे कमांड कंसोल
    क्यू में चल रहा है प्रश्न: जब मैं कंसोल में C: \ windows \ system32 \ tasklist.exe चलाता हूं परिणाम के अक्षर एन्कोडिंग (विंडोज़ शब्दावली में "कोड पेज" क्या है?

    • खिड़कियों "chcp" कोई तर्क के साथ आदेश कंसोल (जैसे बहुभाषी लैटिन -1, 1252 लैटिन -1 के लिए के लिए 850) के लिए सक्रिय कोड पेज संख्या देता है। Windows Microsoft Code Pages, Windows OEM Code Pages, Windows ISO Code Pages
      डिफ़ॉल्ट सिस्टम कोड पृष्ठ मूल रूप से आपके सिस्टम लोकेल के अनुसार सेटअप होता है (इसे देखने के लिए systeminfo टाइप करें या नियंत्रण कक्ष-> क्षेत्र और भाषा)।
      मैं कैसे खिड़कियों कोड से एक जावा बाइट धारा डिकोड करते हैं:
    • विंडोज़ ओएस/नेट समारोह getACP() भी इस जानकारी

  2. जावा हिस्सा देता है "एक्स" का पृष्ठ (उदाहरण के लिए 850 या 1252)?

    • के बीच विंडो कोड पृष्ठ संख्या और बराबर जावा चारसेट नाम पूर्ण मानचित्रण अभ्यास निम्नलिखित उपसर्ग से मानचित्रण प्राप्त करने के लिए जोड़ा जा सकता है में, here - Code Page Identifiers (Windows) से
    • हालांकि प्राप्त किया जा सकता:
      "" (कोई नहीं) आईएसओ के लिए, "आईबीएम" या "एक्स-आईबीएम" OEM के लिए, "विंडोज़-" या "एक्स-विंडोज-" माइक्रोसॉफ्ट/विंडोज के लिए।
      उदा। ISO-8859-1 या IBM850 या विंडोज़-1252

पूर्ण समाधान:

String cmd = System.getenv("windir") + "\\system32\\" + "chcp.com"; 
    Process p = Runtime.getRuntime().exec(cmd); 
    // Use default charset here - only want digits which are "core UTF8/UTF16"; 
    // ignore text preceding ":" 
    String windowsCodePage = new Scanner(
     new InputStreamReader(p.getInputStream())).skip(".*:").next(); 

    Charset charset = null; 
    String[] charsetPrefixes = 
     new String[] {"","windows-","x-windows-","IBM","x-IBM"}; 
    for (String charsetPrefix : charsetPrefixes) { 
     try { 
      charset = Charset.forName(charsetPrefix+windowsCodePage); 
      break; 
     } catch (Throwable t) { 
     } 
    } 
    // If no match found, use default charset 
    if (charset == null) charset = Charset.defaultCharset(); 

    cmd = System.getenv("windir") + "\\system32\\" + "tasklist.exe"; 
    p = Runtime.getRuntime().exec(cmd); 
    InputStreamReader isr = new InputStreamReader(p.getInputStream(), charset); 
    BufferedReader input = new BufferedReader(isr); 

    // Debugging output 
    System.out.println("matched codepage "+windowsCodePage+" to charset name:"+ 
      charset.name()+" displayName:"+charset.displayName()); 
    String line; 
    while ((line = input.readLine()) != null) { 
      System.out.println(line); 
    } 

क्यू के लिए धन्यवाद! - मज़ेदार था।

+0

यह बहुत अच्छा है - मैंने 'notepad.exe' एप्लिकेशन की प्रतिलिपि बनाई और इसे '0aéèçê.exe' पर रीमेन किया और इसे लॉन्च किया। मेरा मूल कोड असफल रहा (वर्ग वर्ण दिखा रहा है)। आपके संस्करण ने सही स्ट्रिंग आउटपुट किया (कोडपेज 850 के साथ)। – assylias

0

चल प्रक्रियाओं की जांच करने, या यहाँ तक कि जावा के माध्यम से ओएस आदेश को चलाने के लिए एक बहुत अच्छा तरीका है।

चार्ससेट के लिए, आप हमेशा समर्थित क्रिससेट के बारे में ओएस पूछ सकते हैं, और Encoder या Decoder अपनी आवश्यकताओं के अनुसार प्राप्त कर सकते हैं।

[संपादित करें] के इसे तोड़ने के नीचे दो; किसी दिए गए स्ट्रिंग के बाइट्स को एन्कोडिंग करने का कोई तरीका नहीं है, इसलिए आपकी एकमात्र पसंद उन बाइट्स को प्राप्त करना है, ऑर्डरिंग को आवश्यकतानुसार बदलें (यदि आप कभी ऐसे माहौल में हैं जहां एक प्रक्रिया आपको एक सरणी दे सकती है अलग-अलग क्रम में बाइट्स, बाइटबफर का उपयोग करने के लिए इसका उपयोग करें), और बाइट्स को उचित आउटपुट में डीकोड करने के लिए समर्थित एकाधिक वर्णसेट डिकोडर्स का उपयोग करें।

यह overkill है और अनुमान लगाने के लिए कि किसी दिए गए उत्पादन UTF-8, UTF-16 या किसी अन्य एन्कोडिंग में हो सकता है की आवश्यकता है। लेकिन कम से कम पर आप संभावित चार्टसेट में से किसी एक का उपयोग करके दिए गए आउटपुट को डीकोड कर सकते हैं, और फिर अपनी आवश्यकताओं के लिए संसाधित आउटपुट का उपयोग करने का प्रयास करें।

चूंकि हम उसी ओएस द्वारा चलाए गए प्रक्रिया के बारे में बात कर रहे हैं जिसमें JVM स्वयं चल रहा है, यह संभव है कि आपका आउटपुट उपलब्ध चार्सेट() विधि द्वारा लौटाए गए वर्णसेट एन्कोडिंग में से एक में होगा।

+0

मैं पहले से ही एक प्रक्रिया का उपयोग कर रहा हूं और मुझे पता है कि एक वर्णमाला कैसे निर्दिष्ट करें। सवाल यह है कि कौन सा अक्षर उपयोग करना है। आप बताते हैं "* आप हमेशा समर्थित चार्टसेट के बारे में ओएस पूछ सकते हैं *": आप यह कैसे करते हैं? मुझे कैसे पता चलेगा कि उस विशिष्ट प्रोग्राम द्वारा समर्थित समर्थित वर्णमाला का उपयोग किस प्रकार किया जाता है? – assylias

+0

आप एक प्रक्रिया का उपयोग कर रहे हैं, लेकिन प्रोसेसबिल्डर नहीं, जो रनटाइम क्लास का उपयोग करने से क्लीनर है। उपलब्ध वर्णमाला प्राप्त करने के लिए आपको कॉल करने के लिए आवश्यक वास्तविक विधि Charset.availableCharsets() है। लेकिन फिर भी, मैंने आपके द्वारा दिए गए javadocs में विधियों का उपयोग करके एक वर्णसेट का परीक्षण करना सुरक्षित होगा - CharsetEncoder।canEncode(), पता लगाएँ(), आदि ... – javabeats

+0

मुझे खेद है, लेकिन मुझे समझ में नहीं आता कि यह कैसे काम करेगा। क्या आप एक साधारण उदाहरण दे सकते हैं कि आप मेरे विशिष्ट उपयोग मामले में अपनी सिफारिश कैसे लागू करेंगे? – assylias

5

दरअसल, tasklist द्वारा उपयोग किया गया वर्णसेट हमेशा सिस्टम डिफ़ॉल्ट से अलग है।

दूसरी ओर, यह जब तक उत्पादन ASCII तक ही सीमित है डिफ़ॉल्ट उपयोग करने के लिए काफी सुरक्षित है। आम तौर पर निष्पादन योग्य मॉड्यूल में उनके नामों में केवल ASCII वर्ण होते हैं।

तो सही स्ट्रिंग्स प्राप्त करने के लिए, आपको (कोड) एएनएसआई) विंडोज कोड पेज को OEM कोड पेज में कनवर्ट करना होगा, और उत्तरार्द्ध को InputStreamReader पर वर्णमाला के रूप में पास करना होगा।

ऐसा लगता है कि इन एन्कोडिंग के बीच कोई व्यापक मैपिंग नहीं है। निम्नलिखित मानचित्रण इस्तेमाल किया जा सकता:

Map<String, String> ansi2oem = new HashMap<String, String>(); 
ansi2oem.put("windows-1250", "IBM852"); 
ansi2oem.put("windows-1251", "IBM866"); 
ansi2oem.put("windows-1252", "IBM850"); 
ansi2oem.put("windows-1253", "IBM869"); 

Charset charset = Charset.defaultCharset(); 
String streamCharset = ansi2oem.get(charset.name()); 
if (streamCharset) { 
    streamCharset = charset.name(); 
} 
InputStreamReader isr = new InputStreamReader(p.getInputStream(), 
               streamCharset); 

यह दृष्टिकोण windows-1251 और IBM866 जोड़ी के साथ मेरे लिए काम किया।

विंडोज द्वारा प्रयोग किया जाता वर्तमान OEM एन्कोडिंग पाने के लिए आपको GetOEMCP फ़ंक्शन का उपयोग कर सकते हैं।वापसी मान ग़ैर-यूनिकोड प्रोग्रामक्षेत्र में प्रशासनिक टैब और भाषा नियंत्रण कक्ष पर स्थापित करने के लिए भाषा पर निर्भर करता है। परिवर्तन लागू करने के लिए रीबूट की आवश्यकता है। ANSI और OEM:


दो विंडोज पर एन्कोडिंग के प्रकार होते हैं।

पूर्व का उपयोग गैर-यूनिकोड अनुप्रयोगों द्वारा जीयूआई मोड में चल रहा है।
उत्तरार्द्ध कंसोल अनुप्रयोगों द्वारा उपयोग किया जाता है। कंसोल अनुप्रयोग उन वर्णों को प्रदर्शित नहीं कर सकते हैं जिन्हें वर्तमान OEM एन्कोडिंग में प्रदर्शित नहीं किया जा सकता है।

चूंकि tasklist कंसोल मोड एप्लिकेशन है, इसका आउटपुट हमेशा मौजूदा OEM एन्कोडिंग में होता है।

अंग्रेजी प्रणालियों के लिए, जोड़ी आमतौर पर Windows-1252 और CP850 है।

जैसा कि मैं रूस में हूं, मेरे सिस्टम में निम्नलिखित एन्कोडिंग हैं: Windows-1251 और CP866
अगर मैं एक फ़ाइल में tasklist के उत्पादन पर कब्जा, फ़ाइल सही सिरिलिक वर्ण प्रदर्शित नहीं कर सकता: (! हाय)

मैं के बजाय ПриветЏаЁўҐв जब नोटपैड में देखी मिलता है।
और µTorrentзTorrent के रूप में प्रदर्शित किया गया है।

आप tasklist द्वारा उपयोग किए गए एन्कोडिंग को नहीं बदल सकते हैं।


हालांकि cmd के आउटपुट एन्कोडिंग को बदलना संभव है। यदि आप /u पर स्विच करते हैं, तो यह यूटीएफ -16 एन्कोडिंग में सब कुछ आउटपुट करेगा। Hi के लिए दो बाइट्स और नई लाइन (\r और \n) के लिए दो बाइट्स:

cmd /c echo Hi>echo.txt 

echo.txt का आकार 4 बाइट है।

cmd /u /c echo Hi>echo.txt 

अब echo.txt का आकार 8 बाइट्स: हर किरदार के दो बाइट्स के साथ प्रतिनिधित्व किया है।

+0

आपके विस्तृत और सूचनात्मक उत्तर के लिए धन्यवाद - मुझे ग्लेन बेस्ट का जवाब इस अर्थ में बेहतर लगता है कि यह एक पूर्ण कार्य उदाहरण प्रदान करता है इसलिए मैंने इसे चुना लेकिन आपका बहुत अच्छा था। – assylias

3

स्पॉइंग प्रक्रियाओं के बजाय JNA के माध्यम से Windows API का उपयोग क्यों नहीं करें? इस तरह:

import com.sun.jna.platform.win32.Kernel32; 
import com.sun.jna.platform.win32.Tlhelp32; 
import com.sun.jna.platform.win32.WinDef; 
import com.sun.jna.platform.win32.WinNT; 
import com.sun.jna.win32.W32APIOptions; 
import com.sun.jna.Native; 

public class ListProcesses { 
    public static void main(String[] args) { 
     Kernel32 kernel32 = (Kernel32) Native.loadLibrary(Kernel32.class, W32APIOptions.UNICODE_OPTIONS); 
     Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();   

     WinNT.HANDLE snapshot = kernel32.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new WinDef.DWORD(0)); 
     try { 
      while (kernel32.Process32Next(snapshot, processEntry)) {    
       System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile)); 
      } 
     } 
     finally { 
      kernel32.CloseHandle(snapshot); 
     } 
    } 
} 

मैंने एक समान उत्तर elsewhere पोस्ट किया।

+0

उपरोक्त केवल कमांड नाम आउटपुट करता है और संपूर्ण कमांड लाइन नहीं। क्या प्रक्रिया पूर्ण कमांड लाइन प्राप्त करने के लिए है? –