Java 如何在Android中以编程方式解压缩文件?
我需要一个小的代码片段,它从一个给定的.zip文件中解压几个文件,并根据压缩文件中的格式给出单独的文件。请发布你的知识并帮助我 Android内置了Java API。检查包裹Java 如何在Android中以编程方式解压缩文件?,java,android,unzip,Java,Android,Unzip,我需要一个小的代码片段,它从一个给定的.zip文件中解压几个文件,并根据压缩文件中的格式给出单独的文件。请发布你的知识并帮助我 Android内置了Java API。检查包裹 这门课是你应该研究的。从ZipInputStream读取ZipEntry并将其转储到文件系统/文件夹中。检查文件。这是我的解压方法,我使用: private boolean unpackZip(String path, String zipname) { InputStream is; Z
这门课是你应该研究的。从ZipInputStream读取ZipEntry并将其转储到文件系统/文件夹中。检查文件。这是我的解压方法,我使用:
private boolean unpackZip(String path, String zipname)
{
InputStream is;
ZipInputStream zis;
try
{
is = new FileInputStream(path + zipname);
zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze;
while((ze = zis.getNextEntry()) != null)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
String filename = ze.getName();
FileOutputStream fout = new FileOutputStream(path + filename);
// reading and writing
while((count = zis.read(buffer)) != -1)
{
baos.write(buffer, 0, count);
byte[] bytes = baos.toByteArray();
fout.write(bytes);
baos.reset();
}
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
这是一个ZipFileIterator(类似于java迭代器,但用于zip文件):
包ch.epfl.bbp.io;
导入java.io.BufferedInputStream;
导入java.io.ByteArrayOutputStream;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileNotFoundException;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.util.Iterator;
导入java.util.zip.ZipEntry;
导入java.util.zip.ZipInputStream;
公共类ZipFileIterator实现了迭代器{
专用字节[]缓冲区=新字节[1024];
私有文件输入流为;
私人Zipinputzis;
私家侦探;
公共ZipFileIterator(文件)引发FileNotFoundException{
is=新文件输入流(文件);
zis=新的ZipInputStream(新的BufferedInputStream(is));
}
@凌驾
公共布尔hasNext(){
试一试{
返回(ze=zis.getNextEntry())!=null;
}捕获(IOE异常){
e、 printStackTrace();
}
返回false;
}
@凌驾
公共文件下一步(){
试一试{
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
整数计数;
字符串文件名=ze.getName();
File tmpFile=File.createTempFile(文件名为“tmp”);
tmpFile.deleteOnExit();//使其可配置
FileOutputStream fout=新的FileOutputStream(tmpFile);
而((计数=zis.read(缓冲区))!=-1){
写入(缓冲区,0,计数);
byte[]bytes=baos.toByteArray();
fout.写入(字节);
重置();
}
fout.close();
zis.closeEntry();
返回tmpFile;
}捕获(例外e){
抛出新的运行时异常(e);
}
}
@凌驾
公共空间删除(){
抛出新的RuntimeException(“未实现”);
}
公众假期结束(){
试一试{
zis.close();
is.close();
}捕获(IOE异常){//nope
}
}
}
对peno的版本进行了一些优化。性能的提高是显而易见的
private boolean unpackZip(String path, String zipname)
{
InputStream is;
ZipInputStream zis;
try
{
String filename;
is = new FileInputStream(path + zipname);
zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null)
{
filename = ze.getName();
// Need to create directories if not exists, or
// it will generate an Exception...
if (ze.isDirectory()) {
File fmd = new File(path + filename);
fmd.mkdirs();
continue;
}
FileOutputStream fout = new FileOutputStream(path + filename);
while ((count = zis.read(buffer)) != -1)
{
fout.write(buffer, 0, count);
}
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
虽然这里已经给出了很好的答案,但我发现它们比我希望的要慢一些。取而代之的是我使用的,我认为这是最好的解决方案,因为它的速度。它还允许对压缩量进行不同的选择,我发现这很有用
public class MainActivity extends Activity {
private String LOG_TAG = MainActivity.class.getSimpleName();
private File zipFile;
private File destination;
private TextView status;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
status = (TextView) findViewById(R.id.main_status);
status.setGravity(Gravity.CENTER);
if ( initialize() ) {
zipFile = new File(destination, "BlueBoxnew.zip");
try {
Unzipper.unzip(zipFile, destination);
status.setText("Extracted to \n"+destination.getAbsolutePath());
} catch (ZipException e) {
Log.e(LOG_TAG, e.getMessage());
} catch (IOException e) {
Log.e(LOG_TAG, e.getMessage());
}
} else {
status.setText("Unable to initialize sd card.");
}
}
public boolean initialize() {
boolean result = false;
File sdCard = new File(Environment.getExternalStorageDirectory()+"/zip/");
//File sdCard = Environment.getExternalStorageDirectory();
if ( sdCard != null ) {
destination = sdCard;
if ( !destination.exists() ) {
if ( destination.mkdir() ) {
result = true;
}
} else {
result = true;
}
}
return result;
}
}
->助手类(unzippers.java)
->xml布局(activity_main.xml):
->Menifest文件中的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
根据瓦西里·索钦斯基的回答,有点小改动&有一个小修正:
public static void unzip(File zipFile, File targetDirectory) throws IOException {
ZipInputStream zis = new ZipInputStream(
new BufferedInputStream(new FileInputStream(zipFile)));
try {
ZipEntry ze;
int count;
byte[] buffer = new byte[8192];
while ((ze = zis.getNextEntry()) != null) {
File file = new File(targetDirectory, ze.getName());
File dir = ze.isDirectory() ? file : file.getParentFile();
if (!dir.isDirectory() && !dir.mkdirs())
throw new FileNotFoundException("Failed to ensure directory: " +
dir.getAbsolutePath());
if (ze.isDirectory())
continue;
FileOutputStream fout = new FileOutputStream(file);
try {
while ((count = zis.read(buffer)) != -1)
fout.write(buffer, 0, count);
} finally {
fout.close();
}
/* if time should be restored as well
long time = ze.getTime();
if (time > 0)
file.setLastModified(time);
*/
}
} finally {
zis.close();
}
}
显著差异
-这是一种可以在任何地方使用的静态实用程序方法公共静态
- 2
参数,因为File
是:/for files,并且无法指定之前提取zip文件的位置。另外String
concatenation>path+filename
-因为-如果真的对它们不感兴趣,请添加一个try-catch抛出
- 实际上,确保所有情况下都存在所需的目录。并非每个zip都包含文件项之前的所有必需目录项。这有两个潜在的bug:
- 如果zip包含一个空目录,并且结果目录中存在一个现有文件,则会忽略该文件。
的返回值很重要mkdirs()
- 可能会在不包含目录的zip文件上崩溃
- 如果zip包含一个空目录,并且结果目录中存在一个现有文件,则会忽略该文件。
- 增加了写缓冲区大小,这将稍微提高性能。存储通常以4k块为单位,而以较小的块为单位写入通常比必要的速度慢
- 使用
的魔力来防止资源泄漏finally
unpackZip("/sdcard/", "pictures.zip")
根据@zapl answer,用进度报告解压:
public interface UnzipFile_Progress
{
void Progress(int percent, String FileName);
}
// unzip(new File("/sdcard/pictures.zip"), new File("/sdcard"));
public static void UnzipFile(File zipFile, File targetDirectory, UnzipFile_Progress progress) throws IOException,
FileNotFoundException
{
long total_len = zipFile.length();
long total_installed_len = 0;
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
try
{
ZipEntry ze;
int count;
byte[] buffer = new byte[1024];
while ((ze = zis.getNextEntry()) != null)
{
if (progress != null)
{
total_installed_len += ze.getCompressedSize();
String file_name = ze.getName();
int percent = (int)(total_installed_len * 100 / total_len);
progress.Progress(percent, file_name);
}
File file = new File(targetDirectory, ze.getName());
File dir = ze.isDirectory() ? file : file.getParentFile();
if (!dir.isDirectory() && !dir.mkdirs())
throw new FileNotFoundException("Failed to ensure directory: " + dir.getAbsolutePath());
if (ze.isDirectory())
continue;
FileOutputStream fout = new FileOutputStream(file);
try
{
while ((count = zis.read(buffer)) != -1)
fout.write(buffer, 0, count);
} finally
{
fout.close();
}
// if time should be restored as well
long time = ze.getTime();
if (time > 0)
file.setLastModified(time);
}
} finally
{
zis.close();
}
}
使用下面的类
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.util.Log;
public class DecompressFast {
private String _zipFile;
private String _location;
public DecompressFast(String zipFile, String location) {
_zipFile = zipFile;
_location = location;
_dirChecker("");
}
public void unzip() {
try {
FileInputStream fin = new FileInputStream(_zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
Log.v("Decompress", "Unzipping " + ze.getName());
if(ze.isDirectory()) {
_dirChecker(ze.getName());
} else {
FileOutputStream fout = new FileOutputStream(_location + ze.getName());
BufferedOutputStream bufout = new BufferedOutputStream(fout);
byte[] buffer = new byte[1024];
int read = 0;
while ((read = zin.read(buffer)) != -1) {
bufout.write(buffer, 0, read);
}
bufout.close();
zin.closeEntry();
fout.close();
}
}
zin.close();
Log.d("Unzip", "Unzipping complete. path : " +_location );
} catch(Exception e) {
Log.e("Decompress", "unzip", e);
Log.d("Unzip", "Unzipping failed");
}
}
private void _dirChecker(String dir) {
File f = new File(_location + dir);
if(!f.isDirectory()) {
f.mkdirs();
}
}
}
如何使用
String zipFile = Environment.getExternalStorageDirectory() + "/the_raven.zip"; //your zip file location
String unzipLocation = Environment.getExternalStorageDirectory() + "/unzippedtestNew/"; // destination folder location
DecompressFast df= new DecompressFast(zipFile, unzipLocation);
df.unzip();
权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我用来将特定文件从zipfile解压到我的应用程序缓存文件夹的最小示例。然后,我使用不同的方法读取清单文件
private void unzipUpdateToCache() {
ZipInputStream zipIs = new ZipInputStream(context.getResources().openRawResource(R.raw.update));
ZipEntry ze = null;
try {
while ((ze = zipIs.getNextEntry()) != null) {
if (ze.getName().equals("update/manifest.json")) {
FileOutputStream fout = new FileOutputStream(context.getCacheDir().getAbsolutePath() + "/manifest.json");
byte[] buffer = new byte[1024];
int length = 0;
while ((length = zipIs.read(buffer))>0) {
fout.write(buffer, 0, length);
}
zipIs .closeEntry();
fout.close();
}
}
zipIs .close();
} catch (IOException e) {
e.printStackTrace();
}
}
受密码保护的Zip文件
val zipFile = File("path_to_your_zip_file")
file.unzip()
如果您想使用密码压缩文件,您可以查看一下可以轻松使用密码压缩文件的:
Zip:
ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);
ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);
RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);
解压缩:
ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);
ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);
RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);
Rar:
ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);
ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);
RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);
这个库的文档已经足够好了,我只是从那里添加了一些示例。
它是完全免费的,专门为android编写。Kotlin way
//FileExt.kt
data class ZipIO (val entry: ZipEntry, val output: File)
fun File.unzip(unzipLocationRoot: File? = null) {
val rootFolder = unzipLocationRoot ?: File(parentFile.absolutePath + File.separator + nameWithoutExtension)
if (!rootFolder.exists()) {
rootFolder.mkdirs()
}
ZipFile(this).use { zip ->
zip
.entries()
.asSequence()
.map {
val outputFile = File(rootFolder.absolutePath + File.separator + it.name)
ZipIO(it, outputFile)
}
.map {
it.output.parentFile?.run{
if (!exists()) mkdirs()
}
it
}
.filter { !it.entry.isDirectory }
.forEach { (entry, output) ->
zip.getInputStream(entry).use { input ->
output.outputStream().use { output ->
input.copyTo(output)
}
}
}
}
}
用法
val zipFile = File("path_to_your_zip_file")
file.unzip()
我正在处理Java的ZipFile类无法处理的zip文件。Java8显然无法处理压缩方法12(我相信是bzip2)。在尝试了包括zip4j在内的许多方法(由于另一个问题,zip4j在处理这些特定文件时也会失败)之后,我成功地使用了支持zip4j的Apache commons compress 请注意,下面的ZipFile类不是java.util.zip中的类 它实际上是org.apache.commons.compress.archivers.zip.ZipFile,所以要小心导入
try (ZipFile zipFile = new ZipFile(archiveFile)) {
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
while (entries.hasMoreElements()) {
ZipArchiveEntry entry = entries.nextElement();
File entryDestination = new File(destination, entry.getName());
if (entry.isDirectory()) {
entryDestination.mkdirs();
} else {
entryDestination.getParentFile().mkdirs();
try (InputStream in = zipFile.getInputStream(entry); OutputStream out = new FileOutputStream(entryDestination)) {
IOUtils.copy(in, out);
}
}
}
} catch (IOException ex) {
log.debug("Error unzipping archive file: " + archiveFile, ex);
}
根据zapl的回答,在
Closeable
周围添加try()
会在使用后自动关闭流
public static void unzip(File zipFile, File targetDirectory) {
try (FileInputStream fis = new FileInputStream(zipFile)) {
try (BufferedInputStream bis = new BufferedInputStream(fis)) {
try (ZipInputStream zis = new ZipInputStream(bis)) {
ZipEntry ze;
int count;
byte[] buffer = new byte[Constant.DefaultBufferSize];
while ((ze = zis.getNextEntry()) != null) {
File file = new File(targetDirectory, ze.getName());
File dir = ze.isDirectory() ? file : file.getParentFile();
if (!dir.isDirectory() && !dir.mkdirs())
throw new FileNotFoundException("Failed to ensure directory: " + dir.getAbsolutePath());
if (ze.isDirectory())
continue;
try (FileOutputStream fout = new FileOutputStream(file)) {
while ((count = zis.read(buffer)) != -1)
fout.write(buffer, 0, count);
}
}
}
}
} catch (Exception ex) {
//handle exception
}
}
使用从Jon Skeet的回答中获得的C#NET 4
中的Constant.DefaultBufferSize
(65536
):
我总是看到帖子使用byte[1024]
或byte[4096]
缓冲区,从来都不知道缓冲区可以大得多,这样可以提高性能,并且仍然正常工作
这是流