Thursday, October 21, 2010

启动一个进程管道输入输出

见下面
import java.io.OutputStream ;
import java.io.InputStream ;
import java.io.OutputStreamWriter ;
import java.io.InputStreamReader ;
import java.io.BufferedReader ;
import java.io.BufferedWriter ;
import java.io.IOException ;

class TestRuntime {

    public static void main( String[] args ) {

        Runtime runtime = Runtime.getRuntime() ;

        try {
            Process proc = runtime.exec( "dot -Tps" ) ;
            OutputStream out = proc.getOutputStream() ;
            InputStream in = proc.getInputStream() ;

            BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( out ) ) ;
            writer.write( "digraph { A->B; B ->C ; A->C }" ) ;
            writer.close() ;

            BufferedReader reader = new BufferedReader( new InputStreamReader( in )  ) ;
            String line = null ;
            while( null != ( line = reader.readLine() ) )
                System.out.println( line ) ;
        } catch( IOException e ) {
            System.exit(1) ;
        }

    }
}
这里以 dot 为例,向其发送一个 digraph 然后输出为一个 ps 文件。

Wednesday, August 25, 2010

JSON Library

JSON 是一种非常通用的数据存放格式。其基本的形式为 "key": "value",并且用 {} 引起来。多个 key 可以用 , 将其分开,另外还有 array 的概念,这一般是用 [] 括起来的相同格式的对象。关于格式进一步的信息可以在其官网获得。这种格式流行的一个主要原因是对各种语言的支持非常全面。这里简单的介绍一下官网上提供的 org.json.* 下面的几个对象。

最重要的当然是 JSONObject 对象,我们可以用常见的字符串创建一个 JSON 的对象,然后通过 get* 方法获得某些键对应的值,而 * 表示的正是在 Java 中的类型,比如 String 等。使用 has() 方法可以测试该对象是否有需要的 key,而 keys() 可以用于遍历一个 JSON 对象的所有 key。其 toString() 方法可以很容易将一个 JSON 对象转换成为文本存放到文件中。

对应的 JSONArray 自然是处理 JSON 中 array 类型的值了。

该库还提供了其他格式的文本,如 XML、CDL(用逗号分割的文本)、HTTP 头、cookie 等转换成为或者从 JSON 转换的能力。

该库在解析错误的时候会抛出 JSONException 异常。

下面是一个简单的 snippet:

import org.json.* ;

import java.util.Iterator ; 

try{
  JSONObject json = new JSONObject( str ) ;
  Iterator<String> iter = json.keys() ;
  while( iter.hasNext() ) {
    String key = iter.next() ; 
    System.out.print( key + ": " + json.getString( key ) ) ;
  }
} catch( JSONException e) {
  System.err.println( "JSON parsing error" ) ; 
}

Sunday, August 22, 2010

Java 中的日志解决方案

Java 里面有一些现成的 logging 库,比如 log4j(apache logging 的子项目),JDK 里面自带的 java.util.logging,以及 jakarta commons 里面的 logging 库 。这样也就诞生了很多 wrapper,或者用 design pattern 的话来说所谓 facade 的东西,比如 org.apache.commons.logging 和 org.slf4j。这两个使用比较容易,一般提供了一个 factory 用于获得 logger(前者为 LogFactory.getLog(),后者为 LoggerFactory.getLogger())。

下面用一个简单的例子说明如何使用 org.apache.commons.logging。
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;

private Log log = LogFactory.getLog( MyClass.class ) ;
if( log.isFatalEnabled() ) 
    log.fatal( "this is a fatal error message") ;

import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ; 

Logger log = LoggerFactory.getLogger( MyClass.class ) ;
log.debug( "something in {} is {}", something, val) ;
类似的还有 info、warn、error、trace 用在不同的情况。

后者提供了几个 hard-wired 的库,如 slf4j-nop(无输出)、slf4j-jdk(使用 java.util.logging)、slf4j-log4j(使用 log4j)、slf4j-simple(使用 System.err)、slf4j-jcl(使用 jakarta commons logging)。通过改变 -cp 就能方便的使用不同的 logger。

值得一提的是在 apache 的 logging 里面不仅仅有 java 的,还有 C++、.net 和 php 的 logger。

Wednesday, August 18, 2010

几个有用的 Java snippet

使用 java.net.* 获得网页:
import java.net.URL;import java.net.URLConnection ;
import java.io.InputStreamReader ;
import java.io.BufferedReader ;
import java.io.IOException ;

URL url = new URL( "your URL" ) ;
URLConnection uc = url.openConnection() ;
BufferedReader reader = new
    BufferedReader( new InputStreamReader( uc.getInputStream() ) ) ;
String line ; 
while( (line = reader.readLine()) != null ){
    // read one line 
}
注意可以用 HttpURLConnection 获得更加细致的控制。

使用 WebCAT 抓去网页,并抽取网页中文本信息:
import pt.tumba.parser.WebCAT ;
import pt.tumba.parser.HTMLParser ;
import pt.tumba.parser.Content ;

HTMLParser parser = new HTMLParser( "profiles" ) ; 
URL url = new URL( "Your URL" ) ;
parser.initTokenizer( url ) ;
parser.processData() ;
Content content = parser.getContent() ; 
System.out.println( content.getText() ) ; 
通过 WebCAT 可以直接 parse 很多格式的东西,比如 PDF、RTF 甚至 SWF 的文本内容。这段代码里面初始化 HTMLParser 的参数是 language profiles 的目录。这个在该 project 的下载的压缩包里面有,利用这些 profile 能够匹配网页的语言类型。比较遗憾的是该库无法确定网页中的哪部分是主体,抽取出来的文字一般会含有其他的信息。比较有用的是里面还有对 link、图片等等的分析。

使用 org.apache.commons.cli.* 解析命令行参数:
import org.apache.commons.cli.* ;
Options options = new Options() ;
options.addOption( "h", false, "Help" ) ;
options.addOption( "o", true, "Output file" ) ;

CommandLineParser parser = new PosixParser() ;
CommandLine cmd = null ;
HelpFormatter formatter = new HelpFormatter() ;
try {
    cmd = parser.parse( options, args) ;
} catch( ParseException e ) {
   System.err.println( "Error in parsing." ) ;
   formatter.printHelp( "TestCLI", options ) ;
   System.exit( 1 ) ;
}

if( cmd.hasOption( "h" ) ) {
    formatter.printHelp( "TestCLI", options ) ;
    System.exit( 1 ) ;
}

if( cmd.hasOption( "o" ) ) {
    // do something                                                                                       
    System.out.println( "output file is " + cmd.getOptionValue( "o" )  ) ;
}

这里有一个非常好的教程。值得注意的是,org.apache.common 是一个非常大的 Java 程序集合,其中有不少好用的东西,比如编码 base64、压缩文件、xml 到 Java 对象的转换等等,值得有空研究一下的。

使用 java.util.Properties 创建简单的配置文件(key=val 形式的文件),并读取其中的内容。
import java.util.Properties ;
import java.util.Set ;
import java.io.FileInputStream ;
import java.io.IOException ;
Properties properties = new Properties() ;
FileInputStream in = null ;

try {
    in = new FileInputStream( "test.conf" ) ;
    properties.load( in ) ;
    in.close() ;
} catch( IOException e ) {
    System.err.println( "Can't open config file" ) ;
    System.exit( 1 ) ;
}

Set<String> keys = properties.stringPropertyNames() ;
for( String key : keys ) {
    System.out.println( key + ": " + properties.getProperty( key ) ) ;
}
另外可以考虑使用 org.apache.commons.configuration.* 做类似的事情。

可能我还是更喜欢 boost::program_options 解决的方案,呵呵。