private static final String ALGORITHM = "AES";
=========================文件加密=================================
/**
* 文件加密
* @param secretKey 文件加密密钥
* @param oldFiles 原始文件列表,需要加密的
* @param newFiles 构造加密后的文件列表
*(选择多个或者单个)多个文件加密
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public void newEncryptFiles(String secretKey, List<File> oldFiles, List<File> newFiles) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException {
// 使用密钥字符串生成秘密密钥
SecretKey secretKeySpec = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
// 获取 AES 加密算法的实例
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 使用秘密密钥初始化密码 cipher,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
//循环复制文件
curr = 1;
for (int i = 0; i < oldFiles.size(); i++) {
File oldFile = oldFiles.get(i);
File newFile = newFiles.get(i);
long m = oldFiles.get(i).length();
int n = (int)(m/100);
int s = 0;//每一份的进度
// 创建输入流,读取源文件
try (InputStream inputStream = new FileInputStream(oldFile);
// 创建输出流,写入加密文件
OutputStream outputStream = new FileOutputStream(newFile);
// 创建密码输出流,连接到输出流,并使用密码 cipher 进行加密
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher)
) {
// 缓冲区大小
byte[] buffer = new byte[4096];
int bytesRead;
// 读取源文件内容到缓冲区
while ((bytesRead = inputStream.read(buffer)) != -1) {
// 将加密后的数据写入加密文件
cipherOutputStream.write(buffer, 0, bytesRead);
s += 1024;
if(s >= n){//进度+1
handler.sendEmptyMessage(MSG_COPY_RUNNING);
prog ++;
s = 0;
}
}
}
}
}
=========================文件解密=========================
SecretKey secretKeySpec = new SecretKeySpec("sin-17214455-@@@".getBytes(), ALGORITHM);
Cipher cipher = null;
try {
cipher = Cipher.getInstance(ALGORITHM + "/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
//获取源加密文件或文件夹路径
File encryptFile= new File(item.getPath() + File.separator + item.getEncrypted_name());
//获取目标解密文件或文件夹路径,解密过后生成的名称original_name
File newFile = new File(item.getNewPath(), "original_name");
// 创建输入流,读取加密文件
FileInputStream inputStream = new FileInputStream(encryptFile);
// 创建输出流,写入解密文件
FileOutputStream outputStream = new FileOutputStream(newFile);
// 创建密码输出流,连接到输出流,并使用密码 cipher 进行加密
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
// 缓冲区大小
byte[] buffer = new byte[4096];
int bytesRead;
// 读取源文件内容到缓冲区
while ((bytesRead = cipherInputStream.read(buffer)) != -1) {
// 将加密后的数据写入解密文件
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
cipherInputStream.close();
if (!newFile.exists()) {
newFile.createNewFile();
}
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
//解密到这里就结束了打开文件,这里就根据自己的需求而定。下面是我自己的一个需求。
// 打开文件,调用系统的打开选择的图片,text文件或者其他
FileUtil.openFile(view.getContext(), newFile, ext);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (NoSuchFileToOpenException e) {
ToastUtil.errorToast(view.getContext(), e.getMessage());
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
/**
* 调用系统应用打开文件
* @param context context
* @param file file对象
* @param ext 扩展名()
* @throws NoSuchFileToOpenException 没有文件异常
*/
public static void openFile(Context context, File file,String ext) throws NoSuchFileToOpenException {
if(! file.exists()){
throw new NoSuchFileToOpenException("文件不存在");
}
//根据扩展名,适配相应的type
String type = getType(ext);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileprovider", file);
intent.setDataAndType(contentUri,type);
} else {
Uri uri = Uri.fromFile(file);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri,type);
}
context.startActivity(intent);
}
/**
* 根据扩展名适配打开类型
* @param ext 文件扩展名
* @return 打开类型
*/
public static String getType(String ext) {
switch (ext){
case "3gp":return "video/3gpp";
case "apk":return "application/vnd.android.package-archive";
case "asf":return "video/x-ms-asf";
case "avi":return "video/x-msvideo";
case "bin":return "application/octet-stream";
case "bmp":return "image/bmp";
case "c":return "text/plain";
case "class":return "application/octet-stream";
case "conf":return "text/plain";
case "cpp":return "text/plain";
case "doc":return "application/msword";
case "docx":return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
case "xls":return "application/vnd.ms-excel";
case "xlsx":return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
case "exe":return "application/octet-stream";
case "gif":return "image/gif";
case "gtar":return "application/x-gtar";
case "gz":return "application/x-gzip";
case "h":return "text/plain";
case "htm":return "text/html";
case "html":return "text/html";
case "jar":return "application/java-archive";
case "java":return "text/plain";
case "jpeg":return "image/jpeg";
case "jpg":return "image/jpeg";
case "js":return "application/x-javascript";
case "log":return "text/plain";
case "m3u":return "audio/x-mpegurl";
case "m4a":return "audio/mp4a-latm";
case "m4b":return "audio/mp4a-latm";
case "m4p":return "audio/mp4a-latm";
case "m4u":return "video/vnd.mpegurl";
case "m4v":return "video/x-m4v";
case "mov":return "video/quicktime";
case "mp2":return "audio/x-mpeg";
case "mp3":return "audio/x-mpeg";
case "mp4":return "video/mp4";
case "mpc":return "application/vnd.mpohun.certificate";
case "mpe":return "video/mpeg";
case "mpeg":return "video/mpeg";
case "mpg":return "video/mpeg";
case "mpg4":return "video/mp4";
case "mpga":return "audio/mpeg";
case "msg":return "application/vnd.ms-outlook";
case "ogg":return "audio/ogg";
case "pdf":return "application/pdf";
case "png":return "image/png";
case "pps":return "application/vnd.ms-powerpoint";
case "ppt":return "application/vnd.ms-powerpoint";
case "pptx":return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
case "prop":return "text/plain";
case "rc":return "text/plain";
case "rmvb":return "audio/x-pn-realaudio";
case "rtf":return "application/rtf";
case "sh":return "text/plain";
case "tar":return "application/x-tar";
case "tgz":return "application/x-compressed";
case "txt":return "text/plain";
case "wav":return "audio/x-wav";
case "wma":return "audio/x-ms-wma";
case "wmv":return "audio/x-ms-wmv";
case "wps":return "application/vnd.ms-works";
case "xml":return "text/plain";
case "z":return "application/x-compress";
case "zip":return "application/x-zip-compressed";
case "":
default:return "*/*";
}
}
在AndroidManiFest注册fileprovider
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
在res目录下的xml里面创建files-path
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="files"
path="." />
<cache-path
name="cache"
path="." />
<!-- <external-path-->
<!-- name="external_storage"-->
<!-- path="." />-->
<external-path
name="file_safe_root_path"
path="." />
<external-files-path
name="external_files"
path="." />
<external-cache-path
name="external_cache"
path="." />
<external-media-path
name="external_media"
path="." />
<root-path
name="root"
path="." />
</paths>