2010-11-25 25 views
12

"बंद करें" मैं एक तरफा लाइब्रेरी का उपयोग कर रहा हूं, दुर्भाग्य से, System.out (या कभी-कभी System.err) पर जानकारी प्रिंट करता है। इसे रोकने का सबसे आसान तरीका क्या है?आउटपुट स्ट्रीम

मैं याद करने के लिए उत्पादन धारा बनाने के बारे में सोच रहा हूँ,, troublemaking तरीकों में से एक के लिए हर कॉल से पहले System.out और err की जगह उन्हें बाद में फिर, और अभी बनाया धारा के बफर ध्यान न दें। क्या कोई आसान, अधिक सुरुचिपूर्ण तरीका है?

संपादित करें: मैं सभी आउटपुट को रीडायरेक्ट नहीं करना चाहता - यह आसानी से पूरा हो गया है। मैं केवल कुछ लाइब्रेरी कॉल द्वारा उत्पन्न आउटपुट को अनदेखा करना चाहता हूं।

उत्तर

16

मैं की तरह कुछ कर रही समाप्त हो गया।

1
File file = new File(filename); 
PrintStream printStream = new PrintStream(new FileOutputStream(file)); 
System.setOut(printStream); 
+0

तो बस इसे एक यादृच्छिक फ़ाइल में डंप करें? और बाद में फ़ाइल हटा दें? थोड़ा अपमानजनक लगता है, क्या यह एक मेमोरी बफर में डंप करना बेहतर नहीं है? – Oak

+0

@ ओक यदि आप संदेशों में रुचि नहीं रखते हैं - प्रिंटस्ट्रीम का विस्तार कैसे करें और कुछ भी (खाली कार्यान्वयन) को अनदेखा करें? – stacker

+0

खाली कार्यान्वयन के साथ सबक्लासिंग वास्तव में अब तक का सबसे अच्छा विचार है - बहुत सरल, अज्ञात वर्ग के साथ बहुत छोटा। – Oak

1

2 तरीके हैं। 1. सबसे आसान तरीका है अपने प्रोग्राम को चलाने और सभी आउटपुट को/dev/null (यदि आप यूनिक्स पर हैं) पर रीडायरेक्ट करते हैं या विशेष फ़ाइल को हटाया जाएगा (विंडोज़ के लिए) इस तरह से सरल है लेकिन इसका मतलब है कि आपका सभी उत्पादन कुछ भी नहीं जा रहा है। यदि आपका प्रोग्राम अच्छी चीजों के लिए STDOUT का उपयोग करता है तो आप इस तरह से उपयोग नहीं कर सकते हैं।

  1. आप जावा एपीआई का उपयोग करके STDOUT सेट कर सकते हैं।

    System.setOut (बाहर) System.setErr (बाहर)

अब आप अपने खुद के OutputStream लागू कर सकते हैं:

import java.io.IOException; 
import java.io.OutputStream; 
import java.util.regex.Pattern; 


public class FilterOutputStream extends OutputStream { 
    private OutputStream out; 
    private Pattern filterOut; 
    public FilterOutputStream(OutputStream out, Pattern filterOut) { 
     this.out = out; 
     this.filterOut = filterOut; 
    } 


    @Override 
    public void write(int b) throws IOException { 
     String callerClassName = new Throwable().getStackTrace()[1].getClassName(); 
     if (filterOut.matcher(callerClassName).find()) { 
      return; 
     } 
     out.write(b); 
    } 

} 

यह बेहतर है, क्योंकि आप अप्रासंगिक उत्पादन को फ़िल्टर कर सकते हैं और अच्छी जानकारी प्रिंट करें।

+2

/dev/null को आउटपुट भेजना एक बुरा विचार है क्योंकि यह एक संदर्भ स्विच को मजबूर करेगा, और प्रदर्शन पर बहुत गंभीर प्रभाव पड़ता है। मैं इसे बेंचमार्क सेंटर में कड़ी मेहनत करता हूं। – stacker

+1

अपवाद का स्टैक ट्रेस बनाना धीमा है, इसलिए यदि आप उस कोड का उपयोग करते हैं तो आपको एप्लिकेशन को प्रोफ़ाइल करना चाहिए। यदि कार्यक्रम सामान्य ऑपरेशन के दौरान कुछ प्रिंट करता है तो 'नई थ्रोबल()' पर कॉल आसानी से बाधा बन सकता है। इसके अलावा आप यह नहीं जान सकते कि किस स्टैक ट्रेस तत्वों को बुलाया गया था, क्योंकि स्टैक फ्रेम की संख्या इस बात पर निर्भर करती है कि किस विधि को मूल रूप से बुलाया गया था, इसलिए कुछ पुनरावृत्तियों की आवश्यकता है। –

4

एक तरह से उन अवांछित प्रिंट से छुटकारा पाने के स्थायी रूप सेबाईटकोड हेरफेर उपयोग करने के लिए परेशानी पुस्तकालय से प्रिंट बयान को दूर करने के लिए होगा। यह उदाहरण के लिए ASM (या अन्य उच्च स्तर में से एक और AOP ढांचे का उपयोग करने में आसान) का उपयोग कर किया जा सकता है।

आप या तो रनटाइम पर या पुस्तकालय की कक्षा फ़ाइलों को फिर से लिखने के एक बार के ऑपरेशन के रूप में कर सकते हैं। कैसे पता लगाने के लिए एएसएम के दस्तावेज़ीकरण का संदर्भ लें। अवधारणा का सबूत यहां है। यह क्या करता है कि यह System.out पर PrintStream के संदर्भ में सभी संदर्भों को प्रतिस्थापित करता है जो कुछ भी नहीं करता है।

पहले परीक्षण। वे my project से कुछ उपयोगिता कक्षाओं का उपयोग बाइटकोड परिवर्तनों के परीक्षण में सहायता के लिए करते हैं (परीक्षण के लिए एक कस्टम क्लास लोडर बनाने और बाइटकोड ट्रांसफॉर्मेशन को दाएं वर्ग में लागू करने की आवश्यकता होती है लेकिन किसी भी अन्य वर्ग नहीं)।

package net.orfjackal.dimdwarf.aop; 

import net.orfjackal.dimdwarf.aop.conf.*; 
import org.junit.*; 
import org.objectweb.asm.*; 
import org.objectweb.asm.util.CheckClassAdapter; 

import java.io.*; 
import java.lang.instrument.ClassFileTransformer; 
import java.lang.reflect.*; 

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.*; 

public class RemoveCallsToSystemOutTest { 

    private PrintStream originalOut; 
    private ByteArrayOutputStream collectedOut; 

    @Before 
    public void collectSystemOut() { 
     originalOut = System.out; 
     collectedOut = new ByteArrayOutputStream(); 
     System.setOut(new PrintStream(collectedOut)); 
    } 

    @After 
    public void restoreOriginalSystemOut() { 
     System.setOut(originalOut); 
    } 

    @Test 
    public void the_target_class_prints_when_not_manipulated() throws Exception { 
     String safetyCheck = callPrintSomething(TroublesomePrinter.class); 

     assertThat(safetyCheck, is("it did execute")); 
     assertThat(collectedOut.size(), is(greaterThan(0))); 
    } 

    @Test 
    public void the_target_class_does_not_print_when_it_has_been_manipulated() throws Exception { 
     String safetyCheck = callPrintSomething(instrumentClass(TroublesomePrinter.class)); 

     assertThat(safetyCheck, is("it did execute")); 
     assertThat(collectedOut.size(), is(0)); 
    } 

    private static String callPrintSomething(Class<?> clazz) throws Exception { 
     Method m = clazz.getMethod("printSomething"); 
     m.setAccessible(true); 
     return (String) m.invoke(null); 
    } 

    private static Class<?> instrumentClass(Class<?> cls) throws ClassNotFoundException { 
     ClassFileTransformer transformer = new AbstractTransformationChain() { 
      protected ClassVisitor getAdapters(ClassVisitor cv) { 
       cv = new CheckClassAdapter(cv); 
       cv = new RemoveCallsToSystemOut(cv); 
       return cv; 
      } 
     }; 
     ClassLoader loader = new TransformationTestClassLoader(cls.getPackage().getName() + ".*", transformer); 
     return loader.loadClass(cls.getName()); 
    } 
} 

class TroublesomePrinter { 
    public static String printSomething() { 
     System.out.println("something"); 
     return "it did execute"; 
    } 
} 

और फिर कार्यान्वयन। कृपया ध्यान दें कि आपको इसे समझने के बिना इस कोड का उपयोग नहीं करना चाहिए। program by coincidence मत करो। मुझे इस छोटे से समाधान के लिए पुनः निर्देशित के लिए

PrintStream out = System.out; 
System.setOut(new PrintStream(new OutputStream() { 
    @Override public void write(int b) throws IOException {} 
})); 
try { 
    <library call> 
} finally { 
    System.setOut(out); 
} 

AlexR के लिए धन्यवाद और स्टेकर:

class SilentSystem { 
    public static final PrintStream out = new PrintStream(new OutputStream() { 
     public void write(int b) { 
     } 
    }); 
} 

class RemoveCallsToSystemOut extends ClassAdapter { 

    public RemoveCallsToSystemOut(ClassVisitor cv) { 
     super(cv); 
    } 

    @Override 
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 
     return new MyMethodAdapter(super.visitMethod(access, name, desc, signature, exceptions)); 
    } 

    private static class MyMethodAdapter extends MethodAdapter { 
     public MyMethodAdapter(MethodVisitor mv) { 
      super(mv); 
     } 

     @Override 
     public void visitFieldInsn(int opcode, String owner, String name, String desc) { 
      if (opcode == Opcodes.GETSTATIC 
        && owner.equals("java/lang/System") 
        && name.equals("out") 
        && desc.equals("Ljava/io/PrintStream;")) { 
       super.visitFieldInsn(opcode, "net/orfjackal/dimdwarf/aop/SilentSystem", name, desc); 
      } else { 
       super.visitFieldInsn(opcode, owner, name, desc); 
      } 
     } 
    } 
} 
+0

मैं एक * सरल * विधि की तलाश में था :) अभी भी, धन्यवाद, यह बहुत दिलचस्प है। – Oak

+0

कुछ जो मुझे कभी नहीं पता था, धन्यवाद किया जा सकता है। – Sid

+0

सरलता दृष्टिकोण के आधार पर निर्भर हो सकती है। ;) यह विधि निश्चित रूप से उन्नत है, लेकिन एक बार जेएआर संसाधित करने के बाद, लाइब्रेरी का उपयोग करना बहुत आसान होगा। दूसरी तरफ System.setOut का उपयोग करने की दूसरी विधि सीखना आसान है, लेकिन रनटाइम पर अप्रत्याशित व्यवहार कर सकता है; यह आसानी से कुछ चीजों को मुद्रित करने से रोक सकता है जिन्हें आप मुद्रित करना चाहते हैं, और कई कोने के मामले हैं, जैसे कि समेकन और एकाधिक धागे से प्रिंटिंग, लाइब्रेरी द्वारा छोड़े गए अपवाद, या यदि आप केवल कुछ छिपाना चाहते हैं लाइब्रेरी द्वारा मुद्रित चीजें और दूसरों को दिखाएं। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^