[Java] System.out lezen

Pagina: 1
Acties:

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 27-05 21:44

Robtimus

me Robtimus no like you

Topicstarter
Ik heb een programma'tje geschreven dat naar System.out print. Nu wil ik echter die output opvangen in een ander progsel, alleen ik krijg het niet goed voor elkaar om een outputstream naar een inputstream te redirecten.

Ik heb het wel geprobeerd met de PipedInputStream en PipedOutputStream, ook met het aanroepen van dat programma'tje in een aparte Thread (zoals wordt aangeraden in de API), maar daarbij kreeg ik deadlock als het programma niet in een aparte Thread wordt gestart en een error ("write end" oid) als ik het wel in een aparte Thread start.

(Natuurlijk had ik wel eerst
Java:
1
System.setOut(new PrintStream(<mijn PipedOutputStream>));
aangeroepen)

Weet iemand hoe het wel kan werken?

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:03
Hoe draai jee de t wee programma's? Als aparte processen? Hoe verbind je hun in- en uitvoer? Met een pipe (|)? Hoe zag je eigen poging met die piped streams eruit? Wat ging daarmee mis?

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 27-05 21:44

Robtimus

me Robtimus no like you

Topicstarter
Ik roep het ene programma aan in het andere programma, dus de enige vorm van piping moet IN de VM zijn. Piping buiten de VM is een makkie, gewoon naar System.out schrijven en System.in lezen.

De code:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.io.*;

public class Test
{
    private static PipedInputStream pin;
    private static PipedOutputStream pout;

    public static void main(String[] args) throws IOException
    {
        pin = new PipedInputStream();
        pout = new PipedOutputStream(pin);
        new Thread(new ExecuteThread()).start();
        StringBuffer buf = new StringBuffer();
        int b;
        while ((b = pin.read()) != -1)
        {
            buf.append(b);
        }
        System.err.println(buf);
    }

    private static class ExecuteThread implements Runnable
    {
        public void run()
        {
            System.setOut(new PrintStream(pout));
            <andere class>.main(new String[] {<parameters>});
        }
    }
}

De error:
code:
1
2
3
4
java.io.IOException: Write end dead
    at java.io.PipedInputStream.read(PipedInputStream.java:213)
    at Test.main(Test.java:15)
Exception in thread "main"
Wat er dus lijkt te gebeuren is dat de output eerder klaar is dan de input, maar aan de output kant (dus in dat andere programma) kan/wil ik niks veranderen.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:03
Ik heb lokaal wat getest en het lijkt erop dat die exception gegooid wordt wanneer geprobeert wordt te lezen uit een lege input stream nadat de thread, die in de output stream schrijft, afgesloten is.

In mijn tests kreeg ik overigens wel altijd alle gegevens binnen, zelf als ik de leeslus vertraagde met een hoop delays (en de schrijvende de thread dus allang afgesloten is als er nog gegevens worden gelezen); de exception komt steeds pas bij de eerste poging om te lezen uit een lege input stream. Je kunt die exception dus als een soort EOF beschouwen.

Dat klopt ook met de documentatie bij PipedInputStream.read():
If a thread was providing data bytes to the connected piped output stream, but the thread is no longer alive, then an IOException is thrown.
Als je in de Java code kijkt, zie je ook dat de streams gekoppeld wordt aan een een readSide en een writeSide Thread object. Het lijkt er dus op dat het mechanisme een beetje lomp en naar mijn idee niet helemaal in overeenstemming met het principe geïmplementeerd is. Zodra je leest van of schrijft naar een pipe, wordt die blijkbaar gekoppeld aan de thread die dat doet en is de pipe alleen nog maar vanuit die thread te benaderen. Niets aan te doen, ben ik bang.

edit:
Ik kan in mijn tests de fout wel omzeilen door in de tweede thread, vlak voordat die afsluit, de outputstream te closen en vervolgens een tijdje te sleepen, zodat de eerste thread tijd heeft om het EOF karakter te lezen. Dit is ook niet ideaal, want feitelijk weet je niet hoe lang je dan moet sleepen, maar gelukkig kan je Thread.join() misbruiken om oneindig te sleepen.

Samenvatting; mijn testcode ziet er als volgt uit en dit werkt mooi zonder exceptions:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.io.*;

public class Test
{
    private static PipedInputStream pin;
    private static PipedOutputStream pout;

    static
    {
        try {
            pin = new PipedInputStream();
            pout = new PipedOutputStream(pin);
        } catch(IOException ioe) {
            ioe.printStackTrace();
        }
    }
        
    public static void main(String[] args) throws IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(pin));
        Thread thread = new Thread(new ExecuteThread());
        thread.start(); 
        String line;
        while((line = reader.readLine()) != null)
            System.err.println("READ: " + line);
        thread.interrupt();
    }
    
    private static class ExecuteThread implements Runnable
    {
        public void run()
        {
            PrintStream oldOut = System.out;
            System.setOut(new PrintStream(pout));
            System.out.println("Foo!");
            System.out.println("Bar?");
            System.out.println("Baz.");
            System.out.close();
            System.setOut(oldOut);
            try {
                Thread.currentThread().join();
            } catch(InterruptedException ie) {
                return;
            }
        }
    }
}

[ Voor 43% gewijzigd door Soultaker op 30-01-2004 21:51 ]


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 27-05 21:44

Robtimus

me Robtimus no like you

Topicstarter
Werkt top! Thx!

More than meets the eye
There is no I in TEAM... but there is ME
system specs