我正在实现一个日志系统,需要使用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>
有没有办法从流中删除发送的数据?或者我应该完全朝另一个方向看?
答案 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会导致错误,因此我还没有找到重用所有内容的方法。