GZIP和UDP中使用Java的大量字符串的最快方法

时间:2012-11-20 16:12:10

标签: java udp gzip bytearrayoutputstream

我正在实现一个日志系统,需要使用GZIP对日志消息进行编码,然后通过UDP发送它们。

到目前为止我得到的是:

初​​始化:

DatagramSocket sock = new DatagramSocket(); 
baos = new ByteArrayOutputStream();
printStream = new PrintStream(new GZIPOutputStream(baos));

然后将此printStream传递出记录器 - 消息将通过它传递

然后每次收到消息时:

byte[] d = baos.toByteArray();
DatagramPacket dp = new DatagramPacket(d,d.length,host,port);
sock.send(dp);

目前让我感到困惑的是,我找不到从ByteArrayOutputStream中删除数据的方法(toByteArray()只获取副本)而且我担心每次重新创建所有三个流对象都会效率低下。 / p>

有没有办法从流中删除发送的数据?或者我应该完全朝另一个方向看?

3 个答案:

答案 0 :(得分:1)

您必须为每封邮件创建一个新流;否则,每次拨打toByteArray()都会再次发送所有先前的消息。

更好的方法可能是用OutputStream包装TCP套接字的GZIPOutputStream

printStream = new PrintStream(new GZIPOutputStream(sock.getOutputStream()));

另外,不要忘记在每条消息后刷新PrintStream,否则不会发生任何事情。

如果速度非常重要,您应该考虑使用DatagramChannel而不是旧(慢)蒸汽API。这应该让你开始:

ByteBuffer buffer = ByteBuffer.allocate( 1000 );
ByteBufferOutputStream bufferOutput = new ByteBufferOutputStream( buffer );
GZIPOutputStream output = new GZIPOutputStream( bufferOutput );
OutputStreamWriter writer = new OutputStreamWriter( output, "UTF-8" );
writer.write( "log message\n" );
writer.close();

sock.getChannel().open(); // do this once
sock.getChannel().write( buffer ); // Send compressed data

注意:您可以通过倒带来重用buffer,但每条消息必须创建一次所有流。

答案 1 :(得分:1)

值得一提的是,如果速度很重要,使用GZIP会有所帮助。 (它会增加一些延迟)

public static void main(String... args) throws IOException {
    test("Hello World");
    test("Nov 20, 2012 4:55:11 PM Main main\n" +
            "INFO: Hello World log message");
}

private static void test(String s) throws IOException {
    byte[] bytes = s.getBytes("UTF-8");
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream outputStream = new GZIPOutputStream(baos);
    outputStream.write(bytes);
    outputStream.close();
    byte[] bytes2 = baos.toByteArray();
    System.out.println("'" + s + "' raw.length=" + bytes.length + " gzip.length=" + bytes2.length);
}

打印

'Hello World' raw.length=11 gzip.length=31
'Nov 20, 2012 4:55:11 PM Main main
INFO: Hello World log message' raw.length=63 gzip.length=80

答案 2 :(得分:0)

答案对我的问题的其他方面很有帮助,但对于实际问题 - 有一种方法可以清除ByteArrayOutputStream中的数据。它有一个reset()方法。它实际上没有清除缓冲区,但它将count属性重置为0,导致它忽略缓冲区中已有的任何数据。

请注意,在重置底层的ByteArrayOutputStream之后写入GZIPOutputStream会导致错误,因此我还没有找到重用所有内容的方法。