通过文件流方式校验文件的md5和下载前服务器计算的是否一致,用于大文件下载后确认是否文件存在损坏。
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
/**
* Created by Android Studio.
* Date: 2023/8/21
* Time: 19:14
* description: 文件md5验证
*
*/
public class VaildHelper {
private static final String TAG = "VaildHelper";
private static VaildHelper sInstance;
private boolean isCancelled = false;
private String taskNum = null;
public static VaildHelper getInstance() {
if (sInstance == null) {
sInstance = new VaildHelper();
}
return sInstance;
}
/**
* 文件校验
*
* @param taskNum
* @param file
* @param md5
* @param callback
*/
public void verify(String taskNum, File file, String md5, IVerifyCallback callback) {
Log.d(TAG, "启动文件校验--》" + taskNum);
if (this.taskNum != null) {
Log.w(TAG, "校验中,取消校验-》" + taskNum);
return;
}
if(file==null||!file.exists()){
Log.w(TAG, "校验的文件不存在-》" + file);
return;
}
this.taskNum = taskNum;
new AsyncTask<Void, Integer, Boolean>() {
@Override
protected Boolean doInBackground(Void... voids) {
if (md5 == null) {
Log.w(TAG, "未提供正确的md5");
return false;
}
String myMd5Str = createChecksum(file.getPath(), "MD5");
Log.i(TAG, "正确md5-》" + md5);
Log.i(TAG, "计算md5-》" + myMd5Str);
if (OtaApplication.IS_DEBUG) {
return true;
}
if (!myMd5Str.equalsIgnoreCase(md5)) {
Log.w(TAG, "校验失败,删除压缩包!");
FileUtils.deleteFile(file.getPath());
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
Log.i(TAG, "校验结果-》" + success);
if (success) {
ResponseHelper.getInstance().sendPackageOk(taskNum);
if (callback != null) {
callback.onSuccess(file);
}
} else {
ResponseHelper.getInstance().sendPackageError(taskNum, ResponseHelper.PackageErrorEnum.VAILD_ERROR);
FileUtils.deleteFile(file.getPath());
}
}
}.execute();
}
/**
* 校验
*
* @param filename 文件名
* @param strType 校验类型--SHA-1,SHA-256,SHA-384,SHA-512,MD5,MD2
* @return byte[]
* @throws Exception
*/
private String createChecksum(String filename, String strType) {
Log.d(TAG, "开始文件校验 ");
StringBuilder result = new StringBuilder();
InputStream fis = null; //将流类型字符串转换为String类型字符串
try {
fis = new FileInputStream(filename); //将流类型字符串转换为String类型字符串
byte[] buffer = new byte[1024 * 10];
MessageDigest complete = MessageDigest.getInstance(strType);
int numRead;
do {
numRead = fis.read(buffer); //从文件读到buffer,最多装满buffer
if (numRead > 0) {
complete.update(buffer, 0, numRead); //用读到的字节进行strType的计算,第二个参数是偏移量
}
if (isCancelled) {
break;
}
} while (numRead != -1);
byte[] bytes = complete.digest();
for (byte b : bytes) {
if (isCancelled) {
isCancelled = false;
break;
}
//加0x100是因为有的b[i]的十六进制只有1位
result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
taskNum = null;
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return result.toString();
}
/**
* 取消
*
* @param taskNum
*/
public void cancle(String taskNum) {
if (TextUtils.isEmpty(taskNum) || !taskNum.equals(this.taskNum)) {
return;
}
Log.w(TAG, "取消验证md5--》" + taskNum);
isCancelled = true;
this.taskNum = null;
}
}