很少,在将 GZIP 压缩字符串发送到 MySQL 服务器并返回后,我会遇到 CRC Mismatch。以下是数据的流动方式。
我的 Android 应用程序中有一个大字符串。我使用将它压缩成一个字节数组
public synchronized static byte[] compress(String str) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
GZIPOutputStream gz_out = new GZIPOutputStream(os);
gz_out.write(str.getBytes());
gz_out.finish();
gz_out.flush();
gz_out.close();
os.flush();
os.close();
byte[] test = os.toByteArray();
String check = decompress(test, false); // making sure CRC Mismatch doesn't occur here.
if (check == null) {
return compress(str);
}
return test;
}
public synchronized static String decompress(byte[] compressed, boolean throwException) {
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 e) {
if (throwException)
throw new RuntimeException("Failed to decompress GZIP.", e);
else {
Log.e(log_tag, "Failed to decompress GZIP.", e);
return null;
}
}
}
我像这样将它发送到我的服务器:
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("data", data);
InputStream is = null;
try {
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 20000);
HttpConnectionParams.setSoTimeout(httpParams, 20000);
HttpClient httpclient = new DefaultHttpClient(httpParams);
HttpPost httppost = new HttpPost(SERVER_ADDRESS + "sendData.php");
httppost.setEntity(builder.build());
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("FriendlyFire", "Error in http connection", e);
return null;
}
// Then read response...
sendData.php 看起来像这样:
//I read the bytes into a variable using
$data = $_POST['data'];
//I create a MySQL connection using
$conn = new mysqli(...);
//I prepare a statement using
$stmt = $conn->prepare("CALL database.saveData(?);");
//I attach the data using
$stmt->bind_param('s', $data);
//I execute the statement using
$stmt->execute();
//I close the statement using
$stmt->close();
//I close the connection using
$conn->close();
MySQL 过程如下所示:
database.saveData(data BLOB)
BEGIN
INSERT INTO Table (columnName) VALUES (data);
END
要将数据下载到我的 Android 应用程序,我这样做:
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 10000);
HttpConnectionParams.setSoTimeout(httpParams, 10000);
HttpClient httpclient = new DefaultHttpClient(httpParams);
HttpPost httppost = new HttpPost(SERVER_ADDRESS + "getData.php");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
byte[] data = EntityUtils.toByteArray(entity);
getData.php 看起来像这样:
$conn = mysqli_connect(...);
$db = mysqli_select_db($conn, "database");
$result = mysqli_query($conn, "CALL database.getData()");
$num_results = mysqli_num_rows($result);
if ($num_results > 0){
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC))
{
$filedata = $row['columnName'];
header("Content-length: ".strlen($filedata));
header("Content-disposition: download; filename=data.bin");
echo $filedata;
}
} else {
echo "EMPTY";
}
getData() 过程如下所示:
database.getData()
BEGIN
SELECT columnName FROM Table LIMIT 1;
END
就像我说的那样,在尝试解压缩从服务器读取的内容后,我时不时会收到 CRC 不匹配错误。我怀疑问题出在我的 PHP 代码中,但也可能出在我的 Android 代码中。我有理由确定 SQL 过程很好。
GZIP 说 99.9% 的问题是由于传输是用 ASCII 而不是二进制完成的。我已尽力将数据保存为二进制,但我一定遗漏了一些东西。就像我说的,我怀疑我的 PHP 代码,尤其是上传代码。我直接从 MySQL 服务器下载了 BLOB,它也给出了 CRC 不匹配错误。
我已经尝试使用 bind_param('b', $data) 准备 mysqli 语句,但是 SQL 表中的结果数据是 0 字节,我在使用 'b' 参数类型时找不到太多内容。我应该使用 _FILES 而不是 _POST 吗?这甚至会有所作为吗?
编辑:我对 Android 和 PHP 上传代码做了进一步的修改:
在 Android 中我改变了
builder.addBinaryBody("data", data);
到
builder.addBinaryBody("data", data, Content.DEFAULT_BINARY, "data.bin");
和 PHP 的变化:
$filename = $_FILES['data']['tmp_name'];
//I create a MySQL connection using
$conn = new mysqli(...);
//I prepare a statement using
$stmt = $conn->prepare("CALL database.saveData(?);");
//I attach the data using
$stmt->bind_param('b', $data);
$fp = fopen($filename, "r");
while ($data = fread($fp, 1024)) {
$stmt2->send_long_data(0, $data);
}
//I execute the statement using
$stmt->execute();
//I close the statement using
$stmt->close();
//I close the connection using
$conn->close();
所以这成功地使用'b'参数将数据发送到MySQL服务器。服务器中的结果数据不为空。我已经下载了数据并成功地对其执行了 gunzip。如果我完全停止得到 CRC 不匹配,我会将其标记为正确答案。