开发者

How can I pipe input to a Java app with Perl?

I need to write a Perl script that pipes input into a Java program. This is related to this, but that didn't help me. My issue is that the Java app doesn't get the print statements until I close the handle. What I found online was that $| needs to be set to something g开发者_JAVA技巧reater than 0, in which case newline characters will flush the buffer. This still doesn't work.

This is the script:

#! /usr/bin/perl -w

use strict;
use File::Basename;

$|=1;

open(TP, "| java -jar test.jar") or die "fail";
sleep(2);

print TP "this is test 1\n";
print TP "this is test 2\n";
print "tests printed, waiting 5s\n";
sleep(5);

print "wait over.  closing handle...\n";
close TP;
print "closed.\n";

print "sleeping for 5s...\n";
sleep(5);
print "script finished!\n";
exit

And here is a sample Java app:

import java.util.Scanner;

public class test{

    public static void main( String[] args ){

        Scanner sc = new Scanner( System.in );
        int crashcount = 0;
        while( true ){
            try{
                String input = sc.nextLine();
                System.out.println( ":: INPUT: " + input );
                if( "bananas".equals(input) ){
                    break;
                }
            } catch( Exception e ){
                System.out.println( ":: EXCEPTION: " + e.toString() );
                crashcount++;
                if( crashcount == 5 ){
                    System.out.println( ":: Looks like stdin is broke" );
                    break;
                }
            }
        }
        System.out.println( ":: IT'S OVER!" );
        return;
    }

}

The Java app should respond to receiving the test prints immediately, but it doesn't until the close statement in the Perl script. What am I doing wrong?

Note: the fix can only be in the Perl script. The Java app can't be changed. Also, File::Basename is there because I'm using it in the real script.


I've grown rather fond of the IO::Handle derived modules. They make it easy to control flushing, reading data, binary mode, and many other aspects of a handle.

In this case we use IO::File.

use IO::File;

my $tp = IO::File->new( "| java -jar test.jar" )
    or die "fail - $!";

# Manual print and flush
$tp->print( 'I am fond of cake' );
$tp->flush;

# print and flush in one method
$tp->printflush( 'I like pie' );

# Set autoflush ON
$tp->autoflush(1);
$tp->print( 'I still like pie' );

Also, since the file handle is lexically scoped, you don't have to close it manually. It will automatically close when it goes out of scope.

BTW, unless you are targeting a perl older than 5.6, you can use the warnings pragma instead of -w. See perllexwarn for more info.


$|=1 only works on the currently selected file handle (by default, STDOUT). To make your TP file handle hot you need to do this after opening it:

select(TP);
$| = 1;
select(STDOUT);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜