|
|
玩篮球的日光灯 · PHP: 程序执行 - Manual· 10 月前 · |
|
|
淡定的柠檬 · Giphy widget for ...· 1 年前 · |
|
|
叛逆的镜子 · 《习近平关于总体国家安全观论述摘编》(二): ...· 1 年前 · |
|
|
彷徨的马铃薯 · 学习ASP.NET Core ...· 1 年前 · |
我需要一个在安卓系统中使用GZip压缩字符串的例子。我想向该方法发送一个类似"hello“的字符串,并获得以下压缩字符串:
BQAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyLmeVlW/w+GphA2BQAAAA==
然后我需要解压它。谁能给我举个例子,完成下面的方法?
private String compressString(String input) {
//...
private String decompressString(String input) {
//...
}
谢谢,
更新
根据 scessor's answer 的说法,我现在有以下4种方法。Android和.net的压缩和解压缩方法。除了一种情况外,这些方法彼此兼容。我的意思是它们在前3个状态下是兼容的,但在第4个状态下是不兼容的:
非状态状态1) ( OK )
3)
有人能解决这个问题吗?
安卓方法:
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;
return "";
}
.Net方法:
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);
}
GZIP方法:
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兼容性,我的代码必须稍微修改一下:
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();
}
您可以使用相同的测试脚本。
不管对BQAAAB+LC压缩的“你好”是什么..。是gzipper的一个特别糟糕的实现。它使用动态块而不是deflate格式的静态块扩展了"Hello“,远远超出了必要的程度。在删除gzip流的4字节前缀(始终以十六进制1f 8b开头)之后,"Hello“被扩展到123字节。在压缩领域,这被认为是一种犯罪。
您抱怨的Compress方法工作正常。它正在生成一个静态块和25字节的总输出。gzip格式具有10个字节的头部和8个字节的尾部开销,使得5个字节的输入被编码为7个字节。那才像话。
不可压缩的流将被扩展,但不应该扩展太多。gzip使用的deflate格式将为不可压缩的数据每16K到64K增加5个字节。
要获得实际的压缩效果,通常需要给压缩器更多的空间来处理这5个字节,这样它就可以在可压缩数据中找到重复的字符串和有偏差的统计数据。我知道你只是在用一个短字符串做测试。但在实际应用程序中,您永远不会使用具有如此短字符串的通用压缩器,因为只发送字符串总是更好。
我在我的项目中尝试了你的代码,在Android上的压缩方法中发现了一个编码错误:
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 );
我对这个问题太着迷了。最后,在我的例子(.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;
}
.Net解压缩
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;
count = stream.Read(buffer, 0, size);
if (count > 0)
memory.Write(buffer, 0, count);
while (count > 0);
return memory.ToArray();
}
Android方法解压不ok
Android Compress -> OK:
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;
}
.Net解压缩-> OK:
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;
count = stream.Read(buffer, 0, size);
if (count > 0)
memory.Write(buffer, 0, count);
while (count > 0);
return memory.ToArray();
}
.Net Compress -> OK:
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);
}
Android解压缩-> Not OK:
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 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
如果你使用的是.NET Framework4.5,这里是你需要的C#类(Base64作为奖励):
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;
}
下面是您需要的Android/Java类:
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);
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((bytesRead = gis.read(data)) != -1) {
baos.write(data, 0, bytesRead);
gis.close();
is.close();
return baos.toString("UTF-8");
} 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.equals(decompressed);
}
至此,你就有了无依赖、100%工作压缩的Android/Java/C#/.NET类。如果你发现 不适用于.NET 4.5 (我已经尝试了从"Hello world“到1000字短篇小说的所有方法)--让我知道。
我在Vb.net中这样做:
Public Function zipString(ByVal Text As String) As String
Dim res As String = ""
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 = ""
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
这可能会很晚,但可能对某些人有用,我最近要求在C#中压缩字符串,然后在Android中解压它。基本上,一个Xamarin android应用程序会向另一个Native Android应用程序发送一个带有压缩额外字符串的intent。Android应用程序在使用之前必须对其进行解压缩。
这些方法对我很有效。
ANDROID解压
public static String decompress(String zipText) throws IOException {
int size = 0;
byte[] gzipBuff = Base64.decode(zipText,Base64.DEFAULT);
ByteArrayInputStream memstream = new ByteArrayInputStream(gzipBuff, 4,gzipBuff.length - 4);
GZIPInputStream gzin = new GZIPInputStream(memstream);
final int buffSize = 8192;
byte[] tempBuffer = new byte[buffSize];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((size = gzin.read(tempBuffer, 0, buffSize)) != -1) {
baos.write(tempBuffer, 0, size);
} byte[] buffer = baos.toByteArray();
baos.close(); return new String(buffer, StandardCharsets.UTF_8);
}
XAMARIN压缩
public static string CompressString(string text)
byte[] buffer = Encoding.UTF8.GetBytes(text);
var memoryStream = new MemoryStream();
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
gZipStream.Write(buffer, 0, buffer.Length);
memoryStream.Position = 0;
var compressedData = new byte[memoryStream.Length];
|
|
玩篮球的日光灯 · PHP: 程序执行 - Manual 10 月前 |