android - मैं GZIPOutputStream का उपयोग कर स्ट्रिंग को ज़िप और अनजिप कैसे कर सकता हूं जो नेट के साथ संगत है?




.net compression (9)

शुरू करने के लिए यहां एक सरल उदाहरण दिया गया है।

public static void main(String[] args) throws IOException 
{
    byte[] buffer = new byte[4096];
    StringBuilder sb = new StringBuilder();

    //read file to compress

    String read = readFile( "spanish.xml", Charset.defaultCharset());

    if( read != null )
    {
        //compress file to output

        FileOutputStream fos = new FileOutputStream("spanish-new.xml");
        GZIPOutputStream gzos = new GZIPOutputStream(fos);
        gzos.write( read.getBytes());
        gzos.close();

        //uncompress and read back

        FileInputStream fis = new FileInputStream("spanish-new.xml");
        GZIPInputStream gzis = new GZIPInputStream(fis);

        int bytes = 0;

        while ((bytes = gzis.read(buffer)) != -1) {
            sb.append( new String( buffer ) );
        }
    }
}

static String readFile(String path, Charset encoding) throws IOException {
    byte[] encoded = Files.readAllBytes(Paths.get(path));
    return new String(encoded, encoding);
}

मुझे एंड्रॉइड में GZip का उपयोग करके एक स्ट्रिंग को संपीड़ित करने के लिए एक उदाहरण की आवश्यकता है। मैं विधि में "हैलो" जैसी स्ट्रिंग भेजना चाहता हूं और निम्न ज़िप्ड स्ट्रिंग प्राप्त करना चाहता हूं:

BQAAAB + LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee ++ 997o7nU4n99 // P1xmZAFs9s5K2smeIYCqyB8 / fnwfPyLmeVlW / w + GphA2BQAAAA ==

तो मुझे इसे डिकंप्रेस करने की ज़रूरत है। क्या कोई मुझे एक उदाहरण दे सकता है और निम्नलिखित विधियों को पूरा कर सकता है?

private String compressString(String input) {
    //...
}

private String decompressString(String input) {
    //...
}

धन्यवाद,

अद्यतन करें

कैसर के जवाब के अनुसार, अब मेरे पास निम्नलिखित 4 विधियां हैं। एंड्रॉइड और .NET संपीड़न और decompress विधियों। ये विधियां एक मामले को छोड़कर एक दूसरे के साथ संगत हैं। मेरा मतलब है कि वे पहले 3 राज्यों में संगत हैं लेकिन चौथे राज्य में असंगत हैं:

  • राज्य 1) ​​Android.compress <-> Android.decompress: ( ठीक है )
  • राज्य 2) Net.compress <-> Net.decompress: ( ठीक है )
  • राज्य 3) Net.compress -> Android.decompress: ( ठीक है )
  • राज्य 4) Android.compress -> .Net.decompress: ( ठीक नहीं है )

क्या कोई इसे हल कर सकता है?

एंड्रॉइड विधियां:

public static String compress(String str) throws IOException {

    byte[] blockcopy = ByteBuffer
            .allocate(4)
            .order(java.nio.ByteOrder.LITTLE_ENDIAN)
            .putInt(str.length())
            .array();
    ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(str.getBytes());
    gos.close();
    os.close();
    byte[] compressed = new byte[4 + os.toByteArray().length];
    System.arraycopy(blockcopy, 0, compressed, 0, 4);
    System.arraycopy(os.toByteArray(), 0, compressed, 4,
            os.toByteArray().length);
    return Base64.encode(compressed);

}

public static String decompress(String zipText) throws IOException {
    byte[] compressed = Base64.decode(zipText);
    if (compressed.length > 4)
    {
        GZIPInputStream gzipInputStream = new GZIPInputStream(
                new ByteArrayInputStream(compressed, 4,
                        compressed.length - 4));

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int value = 0; value != -1;) {
            value = gzipInputStream.read();
            if (value != -1) {
                baos.write(value);
            }
        }
        gzipInputStream.close();
        baos.close();
        String sReturn = new String(baos.toByteArray(), "UTF-8");
        return sReturn;
    }
    else
    {
        return "";
    }
}

नेट तरीकों:

public static string compress(string text)
{
    byte[] buffer = Encoding.UTF8.GetBytes(text);
    MemoryStream ms = new MemoryStream();
    using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
    {
        zip.Write(buffer, 0, buffer.Length);
    }

    ms.Position = 0;
    MemoryStream outStream = new MemoryStream();

    byte[] compressed = new byte[ms.Length];
    ms.Read(compressed, 0, compressed.Length);

    byte[] gzBuffer = new byte[compressed.Length + 4];
    System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
    System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
    return Convert.ToBase64String(gzBuffer);
}

public static string decompress(string compressedText)
{
    byte[] gzBuffer = Convert.FromBase64String(compressedText);
    using (MemoryStream ms = new MemoryStream())
    {
        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

        byte[] buffer = new byte[msgLength];

        ms.Position = 0;
        using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
        {
            zip.Read(buffer, 0, buffer.Length);
        }

        return Encoding.UTF8.GetString(buffer);
    }
}

मैं इस मुद्दे के साथ पागल हो गया। अंत में, मेरे मामले में (.Net 4) .Net संगतता की शुरुआत में इस अतिरिक्त 4 बाइट्स को जोड़ना आवश्यक नहीं था।

यह बस इस तरह काम करता है:

एंड्रॉइड संपीड़न:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

नेट डिकंप्रेस

public static byte[] DecompressViD(byte[] gzip)
    {
        // Create a GZIP stream with decompression mode.
        // ... Then create a buffer and write into while reading from the GZIP stream.
        using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
        {
            const int size = 4096;
            byte[] buffer = new byte[size];
            using (MemoryStream memory = new MemoryStream())
            {
                int count = 0;
                do
                {
                    count = stream.Read(buffer, 0, size);
                    if (count > 0)
                    {
                        memory.Write(buffer, 0, count);
                    }
                }
                while (count > 0);
                return memory.ToArray();
            }
        }
    }

ठीक है, मुझे बहुत सारे मौजूदा उत्तर होने पर चिमटा करने से नफरत है, लेकिन दुर्भाग्यवश उनमें से अधिकतर कारणों से भिन्न हैं:

  • .NET Framework के भीतर GZIP एल्गोरिदम के बीच अंतर हैं। यदि आप .NET 4.5 का उपयोग कर रहे हैं, तो आप विभिन्न उत्तरों में देखे जाने वाली अधिकांश शिकायतों को केवल आपके लिए लागू नहीं करते हैं (बल्कि 2.0 या 3.5 का उपयोग करने वाले लोगों के लिए)। यदि आप कोड के "निश्चित" संस्करणों के साथ जाते हैं तो आप वास्तव में गड़बड़ संपीड़न / डिकंप्रेशन करेंगे।
  • जावा अप्रयुक्त बाइट [] का उपयोग करता है, .NET हस्ताक्षरित बाइट [] का उपयोग करता है। यह परिवहन के दौरान समस्याएं पैदा कर सकता है इस पर निर्भर करता है कि आप वास्तव में उस बाइट को कैसे परिवहन कर रहे हैं []।
  • मैंने बाइट ट्रांसपोर्ट करने के लिए बेस 64 का उपयोग किया है [] जो और भी अधिक समस्याएं पेश कर सकता है। कई अन्य कारण हैं, लेकिन चलो आगे बढ़ते हुए और कोड प्राप्त करें ...

यदि आप .NET Framework 4.5 का उपयोग कर रहे हैं तो यहां सी # कक्षा की आवश्यकता है (बेस 64 को बोनस के रूप में):

public class CompressString
{
    private static void CopyTo(Stream src, Stream dest)
    {
        byte[] bytes = new byte[4096];
        int cnt;

        while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
        {
            dest.Write(bytes, 0, cnt);
        }
    }

    public static byte[] Zip(string str)
    {
        var bytes = Encoding.UTF8.GetBytes(str);

        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gs = new GZipStream(mso, CompressionMode.Compress))
            {
                //msi.CopyTo(gs);
                CopyTo(msi, gs);
            }

            return mso.ToArray();
        }
    }

    public static string Unzip(byte[] bytes)
    {
        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gs = new GZipStream(msi, CompressionMode.Decompress))
            {
                //gs.CopyTo(mso);
                CopyTo(gs, mso);
            }

            return Encoding.UTF8.GetString(mso.ToArray());
        }
    }

    // Base64
    public static string ZipBase64(string compress)
    {
        var bytes = Zip(compress);
        var encoded = Convert.ToBase64String(bytes, Base64FormattingOptions.None);
        return encoded;
    }

    public static string UnzipBase64(string compressRequest)
    {
        var bytes = Convert.FromBase64String(compressRequest);
        var unziped = Unzip(bytes);
        return unziped;
    }

    // Testing
    public static bool TestZip(String stringToTest)
    {
        byte[] compressed = Zip(stringToTest);
        Debug.WriteLine("Compressed to " + compressed.Length + " bytes");
        String decompressed = Unzip(compressed);
        Debug.WriteLine("Decompressed to: " + decompressed);

        return stringToTest == decompressed;
    }
}

और यहां आपको एंड्रॉइड / जावा क्लास की आवश्यकता है:

public class CompressString {
    public static byte[] compress(String string) {
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
            GZIPOutputStream gos = new GZIPOutputStream(os);
            gos.write(string.getBytes());
            gos.close();
            byte[] compressed = os.toByteArray();
            os.close();
            return compressed;
        } catch (IOException ex) {
            return null;
        }
    }

    public static String decompress(byte[] compressed) {
        try {
            final int BUFFER_SIZE = 32;
            ByteArrayInputStream is = new ByteArrayInputStream(compressed);
            GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
            StringBuilder string = new StringBuilder();
            byte[] data = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = gis.read(data)) != -1) {
                string.append(new String(data, 0, bytesRead));
            }
            gis.close();
            is.close();
            return string.toString();
        } catch (IOException ex) {
            return null;
        }
    }    

    // Base64
    public static String compressBase64(String strToCompress) {
        byte[] compressed = compress(strToCompress);
        String encoded = android.util.Base64.encodeToString(compressed, android.util.Base64.NO_WRAP);
        return encoded;
    }

    public static String decompressBase64(String strEncoded) {
        byte[] decoded = android.util.Base64.decode(strEncoded, android.util.Base64.NO_WRAP);
        String decompressed = decompress(decoded);
        return decompressed;
    }


    // test
    public static boolean testCompression(String stringToTest) {
        byte[] compressed = compress(stringToTest);
        Log.d("compress-test", "Compressed to " + compressed.length + " bytes");
        String decompressed = decompress(compressed);
        Log.d("compress-test", "Decompressed to " + decompressed);

        return stringToTest == decompressed;
    }
}

तो, आप वहां जाते हैं - निर्भरता मुक्त, 100% कामकाजी संपीड़न एंड्रॉइड / जावा / सी # / .NET कक्षाएं। यदि आपको स्ट्रिंग मिलती है जो .NET 4.5 के साथ काम नहीं कर रही है (मैंने "हैलो वर्ल्ड" से 1000 शब्द छोटी कहानी से सब कुछ करने की कोशिश की है) - मुझे बताएं।


मैं इसे Vb.net में करता हूं:

  Public Function zipString(ByVal Text As String) As String
    Dim res As String = ""
    Try

        Dim buffer As Byte() = System.Text.Encoding.UTF8.GetBytes(Text)
        Dim ms As New MemoryStream()
        Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, True)
            zipStream.Write(buffer, 0, buffer.Length)
        End Using
        ms.Position = 0
        Dim outStream As New MemoryStream()
        Dim compressed As Byte() = New Byte(ms.Length - 1) {}
        ms.Read(compressed, 0, compressed.Length)
        Dim gzBuffer As Byte() = New Byte(compressed.Length + 3) {}
        System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length)
        System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4)
        res = Convert.ToBase64String(gzBuffer)
    Catch ex As Exception
        Log("mdl.zipString: " & ex.Message)
    End Try
    Return res
End Function

Public Function unzipString(ByVal compressedText As String) As String
    Dim res As String = ""
    Try
        Dim gzBuffer As Byte() = Convert.FromBase64String(compressedText)
        Using ms As New MemoryStream()
            Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
            ms.Write(gzBuffer, 4, gzBuffer.Length - 4)
            Dim buffer As Byte() = New Byte(msgLength - 1) {}
            ms.Position = 0
            Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
                zipStream.Read(buffer, 0, buffer.Length)
            End Using
            res = System.Text.Encoding.UTF8.GetString(buffer, 0, buffer.Length)
        End Using
    Catch ex As Exception
        Log("mdl.unzipString: " & ex.Message)
    End Try
    Return res
End Function

बीक्यूएएएबी + एलसी को संकुचित "हैलो" जो कुछ भी था, वह एक गीजर का विशेष रूप से खराब कार्यान्वयन है। यह डिफ्लेट प्रारूप में स्थिर ब्लॉक के बजाय एक गतिशील ब्लॉक का उपयोग करके, "हैलो" को ज़्यादा से ज़्यादा ज़रूरी है। Gzip स्ट्रीम (जो हमेशा हेक्स 1 एफ 8 बी के साथ शुरू होता है) के लिए चार बाइट उपसर्ग को हटाने के बाद, "हैलो" को 123 बाइट्स तक बढ़ाया गया था। संपीड़न की दुनिया में, इसे अपराध माना जाता है।

जिस कंप्रेस विधि के बारे में आप शिकायत कर रहे हैं वह ठीक से और सही तरीके से काम कर रहा है। यह एक स्थिर ब्लॉक और 25 बाइट्स का कुल उत्पादन उत्पन्न कर रहा है। जीजीआईपी प्रारूप में दस बाइट हेडर और आठ-बाइट ट्रेलर ओवरहेड है, जिससे पांच बाइट इनपुट को सात बाइट्स में कोड किया गया है। यह हुई ना बात।

धाराएं जो संपीड़ित नहीं हैं, का विस्तार किया जाएगा, लेकिन यह बहुत अधिक नहीं होना चाहिए। Gzip द्वारा उपयोग किए गए डिफ्लेट प्रारूप में असम्पीडित डेटा के लिए प्रत्येक 16K से 64K तक पांच बाइट जोड़े जाएंगे।

वास्तविक संपीड़न प्राप्त करने के लिए, सामान्य रूप से आपको कंप्रेसर को उस पांच बाइट्स के साथ काम करने के लिए बहुत कुछ देना होगा, ताकि यह संपीड़ित डेटा में बार-बार तार और पक्षपातपूर्ण आंकड़े पा सकें। मैं समझता हूं कि आप केवल एक छोटी स्ट्रिंग के साथ परीक्षण कर रहे थे। लेकिन एक वास्तविक अनुप्रयोग में, आप कभी भी इस तरह के छोटे तारों के साथ एक सामान्य उद्देश्य कंप्रेसर का उपयोग नहीं करेंगे, क्योंकि स्ट्रिंग को भेजने के लिए हमेशा बेहतर होगा।


मैंने अपने प्रोजेक्ट में अपना कोड आज़माया, और एंड्रॉइड पर संपीड़न विधि में एक एन्कोडिंग बग पाया:

byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(str.length())
        .array();
ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write(str.getBytes());

उपर्युक्त कोड पर, आपको सही एन्कोडिंग का उपयोग करना चाहिए, और बाइट लंबाई को भरना चाहिए, स्ट्रिंग लंबाई नहीं:

byte[] data = str.getBytes("UTF-8");

byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(data.length)
            .array();

ByteArrayOutputStream os = new ByteArrayOutputStream( data.length );    
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write( data );

एंड्रॉइड विधि डिकंप्रेस ठीक नहीं है

एंड्रॉइड संपीड़न -> ठीक है:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

नेट डिकंप्रेस -> ठीक है:

public static byte[] DecompressViD(byte[] gzip)
{
    // Create a GZIP stream with decompression mode.
    // ... Then create a buffer and write into while reading from the GZIP stream.
    using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
    {
        const int size = 4096;
        byte[] buffer = new byte[size];
        using (MemoryStream memory = new MemoryStream())
        {
            int count = 0;
            do
            {
                count = stream.Read(buffer, 0, size);
                if (count > 0)
                {
                    memory.Write(buffer, 0, count);
                }
            }
            while (count > 0);
            return memory.ToArray();
        }
    }
}

नेट कंप्रेस -> ठीक है:

    public static string compress(string text)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(text);
        MemoryStream ms = new MemoryStream();
        using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
        {
            zip.Write(buffer, 0, buffer.Length);
        }

        ms.Position = 0;
        MemoryStream outStream = new MemoryStream();

        byte[] compressed = new byte[ms.Length];
        ms.Read(compressed, 0, compressed.Length);

        return Convert.ToBase64String(compressed);
    }

एंड्रॉइड डिकंप्रेस -> ठीक नहीं है:

public static String decompress(String zipText) throws IOException {
    byte[] compressed = Base64.decode(zipText);

    GZIPInputStream os = new GZIPInputStream(new ByteArrayInputStream(compressed));

    GZIPInputStream gzipInputStream = new GZIPInputStream(os);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    for (int value = 0; value != -1;) {
        value = gzipInputStream.read();
        if (value != -1) {
            baos.write(value);
        }
    }
    gzipInputStream.close();
    baos.close();

    return new String(baos.toByteArray(), "UTF-8");
}

जीजेआईपी विधियों:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    final int BUFFER_SIZE = 32;
    ByteArrayInputStream is = new ByteArrayInputStream(compressed);
    GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    StringBuilder string = new StringBuilder();
    byte[] data = new byte[BUFFER_SIZE];
    int bytesRead;
    while ((bytesRead = gis.read(data)) != -1) {
        string.append(new String(data, 0, bytesRead));
    }
    gis.close();
    is.close();
    return string.toString();
}

और एक परीक्षण:

final String text = "hello";
try {
    byte[] compressed = compress(text);
    for (byte character : compressed) {
        Log.d("test", String.valueOf(character));
    }
    String decompressed = decompress(compressed);
    Log.d("test", decompressed);
} catch (IOException e) {
    e.printStackTrace();
}

=== अपडेट ===

यदि आपको .NET compability की आवश्यकता है तो मेरे कोड को थोड़ा बदलना होगा:

public static byte[] compress(String string) throws IOException {
    byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(string.length())
        .array();
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    os.close();
    byte[] compressed = new byte[4 + os.toByteArray().length];
    System.arraycopy(blockcopy, 0, compressed, 0, 4);
    System.arraycopy(os.toByteArray(), 0, compressed, 4, os.toByteArray().length);
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    final int BUFFER_SIZE = 32;
    ByteArrayInputStream is = new ByteArrayInputStream(compressed, 4, compressed.length - 4);
    GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    StringBuilder string = new StringBuilder();
    byte[] data = new byte[BUFFER_SIZE];
    int bytesRead;
    while ((bytesRead = gis.read(data)) != -1) {
        string.append(new String(data, 0, bytesRead));
    }
    gis.close();
    is.close();
    return string.toString();
}

आप एक ही टेस्ट स्क्रिप्ट का उपयोग कर सकते हैं।


आप एमुलेटर शुरू करने के लिए निम्नलिखित कमांड के साथ emulator.bat बना सकते हैं। यह तेजी से शुरू हो जाएगा।

emulator.exe -cpu-delay 0 -no-boot-anim @<avd name>

या यूनिक्स (मैक या लिनक्स स्वाद) पर:

emulator -cpu-delay 0 -no-boot-anim @<avd name>






android .net compression zip gzip