压缩要通过 RMI 发送的 Java HashMap

发布于 2024-10-04 01:44:57 字数 168 浏览 3 评论 0原文

我们有一个通过 RMI 进行通信的客户端/服务器应用程序。服务器将 HashMap 发送到客户端。一切正常,但是当发送大型 HashMap 时,传输时间可能会很慢。

有没有办法在发送之前压缩HashMap,然后在客户端解压?我不想在磁盘上创建任何文件(所有文件都必须位于 RAM 中)

谢谢

We have a Client/Server application which communicates over RMI. The server sends HashMaps to the client. All works well, however when sending large HashMaps, transfer times can be slow.

Is there any way to compress the HashMaps before sending, then decompress on the client? I do not want to create any files on disk whatsoever (All must be in RAM)

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

马蹄踏│碎落叶 2024-10-11 01:44:57

您可以将 DeflatorOutputStream 用于 ByteArrayOutputStream,但是您最终会得到一个 byte[],因此您的 RMI 调用应该返回一个 byte[]。

小的可序列化对象不能很好地压缩,但是如果您有许多可序列化对象,它可以很好地压缩。大量文本也是如此。

最简单的事情就是尝试一下。如果存在重复的字符串甚至部分字符串,这将有助于压缩。

public static void main(String... args) throws IOException {
    Map<String, String> map = new HashMap<String, String>();

    for(int i=0;i<1000;i++)
        map.put(""+Math.random(), ""+Math.random());
    byte[] bytes1 = toBytes(map);
    byte[] bytes2 = toCompressedBytes(map);
    System.out.println("HashMap with "+map.size()+" entries, Uncompressed length="+bytes1.length+", compressed length="+bytes2.length);
}

public static byte[] toCompressedBytes(Object o) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(new DeflaterOutputStream(baos));
    oos.writeObject(o);
    oos.close();
    return baos.toByteArray();
}

public static byte[] toBytes(Object o) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(o);
    oos.close();
    return baos.toByteArray();
}

public static Object fromCompressedBytes(byte[] bytes) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new InflaterInputStream(new ByteArrayInputStream(bytes)));
    return ois.readObject();
}

印刷

HashMap with 1000 entries, Uncompressed length=42596, compressed length=19479

You can use DeflatorOutputStream to a ByteArrayOutputStream, however you will end up with a byte[] so your RMI call should return a byte[].

Small serializable obejct won't compress well, however if you have many Serializable objects it can compress very well. So can large amounts of text.

The simplest thing to do is to try it. If there are repeated strings or even portions of strings, this will help compression.

public static void main(String... args) throws IOException {
    Map<String, String> map = new HashMap<String, String>();

    for(int i=0;i<1000;i++)
        map.put(""+Math.random(), ""+Math.random());
    byte[] bytes1 = toBytes(map);
    byte[] bytes2 = toCompressedBytes(map);
    System.out.println("HashMap with "+map.size()+" entries, Uncompressed length="+bytes1.length+", compressed length="+bytes2.length);
}

public static byte[] toCompressedBytes(Object o) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(new DeflaterOutputStream(baos));
    oos.writeObject(o);
    oos.close();
    return baos.toByteArray();
}

public static byte[] toBytes(Object o) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(o);
    oos.close();
    return baos.toByteArray();
}

public static Object fromCompressedBytes(byte[] bytes) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new InflaterInputStream(new ByteArrayInputStream(bytes)));
    return ois.readObject();
}

Prints

HashMap with 1000 entries, Uncompressed length=42596, compressed length=19479
人生戏 2024-10-11 01:44:57

不要对哈希图做任何事情。相反,编写自定义套接字工厂使用 DeflaterOutputStream 压缩数据。

Don't do anything to the hashmap. Instead, Write a custom socket factory that compresses the data using a DeflaterOutputStream.

微暖i 2024-10-11 01:44:57

许多年前,我曾经将对象序列化为字节数组,然后对其进行压缩。 Java 仍然支持 Zip :) 所以尝试这个方法。

Many years ago I used to serialize objects into byte array and then zip it. Zip is still supported by Java :) so try this method.

魂归处 2024-10-11 01:44:57

您可以尝试对哈希图中的元素使用自定义序列化机制

您要发送什么样的信息?里面的物体是什么样子的?

即使使用默认机制,并将所有不需要的属性标记为瞬态也会有所帮助。

此外,您可以尝试将自己序列化的数据发送到 ZipOutputStream 但我会将其作为最后一个资源,因为二进制内容不会压缩太多。

编辑

由于您仅使用字符串,因此您可以创建一个包装器,其自定义序列化是一个压缩数组(与 Peter Lawrey 的答案非常相似),但是,使用自定义序列化可以让您封装序列化过程并拥有它对 RMI 进行一些“透明”的工作(RMI 序列化永远不会知道您正在使用压缩版本)

这是一个演示:

import java.io.*;
import java.util.*;
import java.util.zip.*;

public class MapDemo implements Serializable { 

    private Map<String,String> map = new HashMap<String,String>();
    // only for demo/comparison purposes, default would use compressoin always
    private boolean useCompression;
    public MapDemo( Map<String,String> map , boolean compressed ) { 
        this.map = map;
        this.useCompression = compressed;
    }

   // This is the custom serialization using compression 
   private void writeObject(ObjectOutputStream out) throws IOException {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();

     OutputStream os = useCompression ?  new DeflaterOutputStream( baos ) : baos;

     ObjectOutputStream oos     = new ObjectOutputStream(  os );
     oos.writeObject( this.map  );
     oos.close();

     out.write( baos.toByteArray() );
   }
}

class Main { 
    public static void main( String [] args )  throws IOException { 
        Map<String,String> regular    = new HashMap<String,String>();
        Map<String,String> compressed = new HashMap<String,String>();
        Random r = new Random();
        for( int i = 0 ; i < 100000 ; i++ ) { 
            String key      = ""+r.nextInt(1000000);
            String value    = ""+r.nextInt(1000000) ;
            // put the same info 
            compressed.put( key , value );
            regular.put( key , value );
        }   
        save( new MapDemo( compressed, true ) , "map.compressed");
        save( new MapDemo( regular, false ) , "map.regular");
    }
    private static void save( Object o, String toFile ) throws IOException  { 
        // This is similar to what RMI serialization would do behind scenes
        ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(toFile));
        oos.writeObject( o );
        oos.close();
    }

}

You may try a custom serialization mechanism for the elements inside the hashmap.

What kind of information are you sending? how do the object inside look like?

Even using the default mechanism, and marking all the unneeded attributes as transient will help.

Additionally you may attempt to sending the data your self serializing it before to a ZipOutputStream but I would let that as a last resource, for the binary content won't compress too much.

EDIT

Since your using only strings, you can create an wrapper whose custom serialization is a compressed array ( pretty much as Peter Lawrey answer ) but, using a custom serialization would let you encapsulate the serialization process and have it working some how "transparently" for RMI ( RMI serialization would never know you're using a compressed version )

Here's a demo:

import java.io.*;
import java.util.*;
import java.util.zip.*;

public class MapDemo implements Serializable { 

    private Map<String,String> map = new HashMap<String,String>();
    // only for demo/comparison purposes, default would use compressoin always
    private boolean useCompression;
    public MapDemo( Map<String,String> map , boolean compressed ) { 
        this.map = map;
        this.useCompression = compressed;
    }

   // This is the custom serialization using compression 
   private void writeObject(ObjectOutputStream out) throws IOException {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();

     OutputStream os = useCompression ?  new DeflaterOutputStream( baos ) : baos;

     ObjectOutputStream oos     = new ObjectOutputStream(  os );
     oos.writeObject( this.map  );
     oos.close();

     out.write( baos.toByteArray() );
   }
}

class Main { 
    public static void main( String [] args )  throws IOException { 
        Map<String,String> regular    = new HashMap<String,String>();
        Map<String,String> compressed = new HashMap<String,String>();
        Random r = new Random();
        for( int i = 0 ; i < 100000 ; i++ ) { 
            String key      = ""+r.nextInt(1000000);
            String value    = ""+r.nextInt(1000000) ;
            // put the same info 
            compressed.put( key , value );
            regular.put( key , value );
        }   
        save( new MapDemo( compressed, true ) , "map.compressed");
        save( new MapDemo( regular, false ) , "map.regular");
    }
    private static void save( Object o, String toFile ) throws IOException  { 
        // This is similar to what RMI serialization would do behind scenes
        ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(toFile));
        oos.writeObject( o );
        oos.close();
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文