有两种方法一种是Android Open Source Project 开源的util 可以不用解压解析zip
package llage2.utils;/** Copyright (C) 2012 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** .0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
t.res.AssetFileDescriptor;
import android.os.ParcelFileDescriptor;
import android.util.Log;import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;public class ZipResourceFile {//// Read-only access to Zip archives, with minimal heap allocation.//static final String LOG_TAG = "zipro";static final boolean LOGV = false;private static final String TAG = "ZipResourceFile";// 4-byte numberstatic private int swapEndian(int i){return ((i & 0xff) << 24) + ((i & 0xff00) << 8) + ((i & 0xff0000) >>> 8)+ ((i >>> 24) & 0xff);}// 2-byte numberstatic private int swapEndian(short i){return ((i & 0x00FF) << 8 | (i & 0xFF00) >>> 8);}/** Zip file constants.*/static final int kEOCDSignature = 0x06054b50;static final int kEOCDLen = 22;static final int kEOCDNumEntries = 8; // offset to #of entries in filestatic final int kEOCDSize = 12; // size of the central directorystatic final int kEOCDFileOffset = 16; // offset to central directorystatic final int kMaxCommentLen = 65535; // longest possible in ushortstatic final int kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);static final int kLFHSignature = 0x04034b50;static final int kLFHLen = 30; // excluding variable-len fieldsstatic final int kLFHNameLen = 26; // offset to filename lengthstatic final int kLFHExtraLen = 28; // offset to extra lengthstatic final int kCDESignature = 0x02014b50;static final int kCDELen = 46; // excluding variable-len fieldsstatic final int kCDEMethod = 10; // offset to compression methodstatic final int kCDEModWhen = 12; // offset to modification timestampstatic final int kCDECRC = 16; // offset to entry CRCstatic final int kCDECompLen = 20; // offset to compressed lengthstatic final int kCDEUncompLen = 24; // offset to uncompressed lengthstatic final int kCDENameLen = 28; // offset to filename lengthstatic final int kCDEExtraLen = 30; // offset to extra lengthstatic final int kCDECommentLen = 32; // offset to comment lengthstatic final int kCDELocalOffset = 42; // offset to local hdrstatic final int kCompressStored = 0; // no compressionstatic final int kCompressDeflated = 8; // standard deflate/** The values we return for ZipEntryRO use 0 as an invalid value, so we want* to adjust the hash table index by a fixed amount. Using a large value* helps insure that people don't mix & match arguments, e.g. to* findEntryByIndex().*/static final int kZipEntryAdj = 10000;static public final class ZipEntryRO {public ZipEntryRO(final String zipFileName, final File file, final String fileName) {mFileName = fileName;mZipFileName = zipFileName;mFile = file;}public final File mFile;public final String mFileName;public final String mZipFileName;public long mLocalHdrOffset; // offset of local file header/* useful stuff from the directory entry */public int mMethod;public long mWhenModified;public long mCRC32;public long mCompressedLength;public long mUncompressedLength;public long mOffset = -1;public void setOffsetFromFile(RandomAccessFile f, ByteBuffer buf) throws IOException {long localHdrOffset = mLocalHdrOffset;try {f.seek(localHdrOffset);f.readFully(buf.array());if (Int(0) != kLFHSignature) {Log.w(LOG_TAG, "didn't find signature at start of lfh");throw new IOException();}int nameLen = Short(kLFHNameLen) & 0xFFFF;int extraLen = Short(kLFHExtraLen) & 0xFFFF;mOffset = localHdrOffset + kLFHLen + nameLen + extraLen;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException ioe) {ioe.printStackTrace();}}/*** Calculates the offset of the start of the Zip file entry within the* Zip file.* * @return the offset, in bytes from the start of the file of the entry*/public long getOffset() {return mOffset;}/*** isUncompressed* * @return true if the file is stored in uncompressed form*/public boolean isUncompressed() {return mMethod == kCompressStored;}public AssetFileDescriptor getAssetFileDescriptor() {if (mMethod == kCompressStored) {ParcelFileDescriptor pfd;try {pfd = ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_READ_ONLY);return new AssetFileDescriptor(pfd, getOffset(), mUncompressedLength);} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return null;}public String getZipFileName() {return mZipFileName;}public File getZipFile() {return mFile;}}public HashMap<String, ZipEntryRO> mHashMap = new HashMap<String, ZipEntryRO>();/* for reading compressed files */public HashMap<File, ZipFile> mZipFiles = new HashMap<File, ZipFile>();public ZipResourceFile(String zipFileName) throws IOException {addPatchFile(zipFileName);}ZipEntryRO[] getEntriesAt(String path) {Vector<ZipEntryRO> zev = new Vector<ZipEntryRO>();Collection<ZipEntryRO> values = mHashMap.values();if (null == path)path = "";int length = path.length();for (ZipEntryRO ze : values) {if (ze.mFileName.startsWith(path)) {if (-1 == ze.mFileName.indexOf('/', length)) {zev.add(ze);}}}ZipEntryRO[] entries = new ZipEntryRO[zev.size()];Array(entries);}public ZipEntryRO[] getAllEntries() {Collection<ZipEntryRO> values = mHashMap.values();Array(new ZipEntryRO[values.size()]);}/*** getAssetFileDescriptor allows for ZipResourceFile to directly feed* Android API's that want an fd, offset, and length such as the* MediaPlayer. It also allows for the class to be used in a content* provider that can feed video players. The file must be stored* (non-compressed) in the Zip file for this to work.* * @param assetPath* @return the asset file descriptor for the file, or null if the file isn't* present or is stored compressed*/public AssetFileDescriptor getAssetFileDescriptor(String assetPath) {ZipEntryRO entry = (assetPath);if (null != entry) {AssetFileDescriptor();}return null;}/*** getInputStream returns an AssetFileDescriptor.AutoCloseInputStream* associated with the asset that is contained in the Zip file, or a* standard ZipInputStream if necessary to uncompress the file* * @param assetPath* @return an input stream for the named asset path, or null if not found* @throws IOException*/public InputStream getInputStream(String assetPath) throws IOException {ZipEntryRO entry = (assetPath);if (null != entry) {if (entry.isUncompressed()) {AssetFileDescriptor().createInputStream();} else {ZipFile zf = (ZipFile());/** read compressed files **/if (null == zf) {zf = new ZipFile(), ZipFile.OPEN_READ);mZipFiles.ZipFile(), zf);}ZipEntry zi = zf.getEntry(assetPath);if (null != zi)InputStream(zi);}}return null;}ByteBuffer mLEByteBuffer = ByteBuffer.allocate(4);static private int read4LE(RandomAccessFile f) throws EOFException, IOException {return adInt());}/** Opens the specified file read-only. We memory-map the entire thing and* close the file before returning.*/void addPatchFile(String zipFileName) throws IOException{File file = new File(zipFileName);RandomAccessFile f = new RandomAccessFile(file, "r");long fileLength = f.length();if (fileLength < kEOCDLen) {throw new IOException();}long readAmount = kMaxEOCDSearch;if (readAmount > fileLength)readAmount = fileLength;/** Make sure this is a Zip archive.*/f.seek(0);int header = read4LE(f);if (header == kEOCDSignature) {Log.i(LOG_TAG, "Found Zip archive, but it looks empty");throw new IOException();} else if (header != kLFHSignature) {Log.v(LOG_TAG, "Not a Zip archive");throw new IOException();}/** Perform the traditional EOCD snipe hunt. We're searching for the End* of Central Directory magic number, which appears at the start of the* EOCD block. It's followed by 18 bytes of EOCD stuff and up to 64KB of* archive comment. We need to read the last part of the file into a* buffer, dig through it to find the magic number, parse some values* out, and use those to determine the extent of the CD. We start by* pulling in the last part of the file.*/long searchStart = fileLength - readAmount;f.seek(searchStart);ByteBuffer bbuf = ByteBuffer.allocate((int) readAmount);byte[] buffer = bbuf.array();f.readFully(buffer);der(ByteOrder.LITTLE_ENDIAN);/** Scan backward for the EOCD magic. In an archive without a trailing* comment, we'll find it on the first try. (We may want to consider* doing an initial minimal read; if we don't find it, retry with a* second read as above.)*/// EOCD == 0x50, 0x4b, 0x05, 0x06int eocdIdx;for (eocdIdx = buffer.length - kEOCDLen; eocdIdx >= 0; eocdIdx--) {if (buffer[eocdIdx] == 0x50 && Int(eocdIdx) == kEOCDSignature){if (LOGV) {Log.v(LOG_TAG, "+++ Found EOCD at index: " + eocdIdx);}break;}}if (eocdIdx < 0) {Log.d(LOG_TAG, "Zip: EOCD not found, " + zipFileName + " is not zip");}/** Grab the CD offset and size, and the number of entries in the* archive. After that, we can release our EOCD hunt buffer.*/int numEntries = Short(eocdIdx + kEOCDNumEntries);long dirSize = Int(eocdIdx + kEOCDSize) & 0xffffffffL;long dirOffset = Int(eocdIdx + kEOCDFileOffset) & 0xffffffffL;// Verify that they look reasonable.if (dirOffset + dirSize > fileLength) {Log.w(LOG_TAG, "bad offsets (dir " + dirOffset + ", size " + dirSize + ", eocd "+ eocdIdx + ")");throw new IOException();}if (numEntries == 0) {Log.w(LOG_TAG, "empty archive?");throw new IOException();}if (LOGV) {Log.v(LOG_TAG, "+++ numEntries=" + numEntries + " dirSize=" + dirSize + " dirOffset="+ dirOffset);}MappedByteBuffer directoryMap = f.getChannel().map(FileChannel.MapMode.READ_ONLY, dirOffset, dirSize);der(ByteOrder.LITTLE_ENDIAN);byte[] tempBuf = new byte[0xffff];/** Walk through the central directory, adding entries to the hash table.*/int currentOffset = 0;/** Allocate the local directory information*/ByteBuffer buf = ByteBuffer.allocate(kLFHLen);der(ByteOrder.LITTLE_ENDIAN);for (int i = 0; i < numEntries; i++) {if (Int(currentOffset) != kCDESignature) {Log.w(LOG_TAG, "Missed a central dir sig (at " + currentOffset + ")");throw new IOException();}/* useful stuff from the directory entry */int fileNameLen = Short(currentOffset + kCDENameLen) & 0xffff;int extraLen = Short(currentOffset + kCDEExtraLen) & 0xffff;int commentLen = Short(currentOffset + kCDECommentLen) & 0xffff;/* get the CDE filename */directoryMap.position(currentOffset + kCDELen);(tempBuf, 0, fileNameLen);directoryMap.position(0);/* UTF-8 on Android */String str = new String(tempBuf, 0, fileNameLen);if (LOGV) {Log.v(LOG_TAG, "Filename: " + str);}ZipEntryRO ze = new ZipEntryRO(zipFileName, file, str);ze.mMethod = Short(currentOffset + kCDEMethod) & 0xffff;ze.mWhenModified = Int(currentOffset + kCDEModWhen) & 0xffffffffL;ze.mCRC32 = Long(currentOffset + kCDECRC) & 0xffffffffL;ze.mCompressedLength = Long(currentOffset + kCDECompLen) & 0xffffffffL;ze.mUncompressedLength = Long(currentOffset + kCDEUncompLen) & 0xffffffffL;ze.mLocalHdrOffset = Int(currentOffset + kCDELocalOffset) & 0xffffffffL;// set the offsetsbuf.clear();ze.setOffsetFromFile(f, buf);// put file into hashmHashMap.put(str, ze);// go to next directory entrycurrentOffset += kCDELen + fileNameLen + extraLen + commentLen;}if (LOGV) {Log.v(LOG_TAG, "+++ zip good scan " + numEntries + " entries");}}
}
package llage2.utils;
/** Copyright (C) 2012 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** .0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/t.Context;
import android.os.Environment;import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;public class APKExpansionSupport {// The shared path to all app expansion filesprivate final static String EXP_PATH = "/Android/obb/";public static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) {String packageName = PackageName();Vector<String> ret = new Vector<String>();if (ExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {// Build the full path to the app's expansion filesFile root = ExternalStorageDirectory();File expPath = new String() + EXP_PATH + packageName);// Check that expansion file path existsif (ists()) {if ( mainVersion > 0 ) {String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb";File main = new File(strMainPath);if ( main.isFile() ) {ret.add(strMainPath);}}if ( patchVersion > 0 ) {String strPatchPath = expPath + File.separator + "patch." + mainVersion + "." + packageName + ".obb";File main = new File(strPatchPath);if ( main.isFile() ) {ret.add(strPatchPath);}}}}String[] retArray = new String[ret.size()];Array(retArray);return retArray;}static public ZipResourceFile getResourceZipFile(String[] expansionFiles) throws IOException {ZipResourceFile apkExpansionFile = null;for (String expansionFilePath : expansionFiles) {if ( null == apkExpansionFile ) {apkExpansionFile = new ZipResourceFile(expansionFilePath);} else {apkExpansionFile.addPatchFile(expansionFilePath);}}return apkExpansionFile;}static public ZipResourceFile getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion) throws IOException{String[] expansionFiles = getAPKExpansionFiles(ctx, mainVersion, patchVersion);return getResourceZipFile(expansionFiles);}public static String readDataFile(String file) throws Exception {//截取路径的文件名 resString fileName = file.substring(file.length() - 9, file.length() - 4);ZipFile zf = new ZipFile(file);InputStream in = new BufferedInputStream(new FileInputStream(file));ZipInputStream zin = new ZipInputStream(in);ZipEntry ze;while ((ze = NextEntry()) != null) {if (ze.isDirectory()) {//Do nothing} else {if (ze.getName().equals(fileName + "describe")) {BufferedReader br = new BufferedReader(new InputStream(ze)));String line;while ((line = br.readLine()) != null) {return line;}br.close();}}}zin.closeEntry();return "";}
}
另外一种可以通过zipFile和ZipOutputStream解析zip,ZipFile和ZipOutputStream解压zip的区别在于正常情况下都是用zipFile解压zip,但是在从网络中下载zip边下载边解压的时候是用ZipOutputStream是最理想的选择。这个就是解压缩zip文件的工具类
/*** 解压zip到指定的路径* @param zipFileString ZIP的名称* @param outPathString 要解压缩路径* @throws Exception*/
public static void UnZipFolder(String zipFileString, String outPathString) throws Exception {ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString));ZipEntry zipEntry;String szName = "";while ((zipEntry = NextEntry()) != null) {szName = Name();if (zipEntry.isDirectory()) {//获取部件的文件夹名szName = szName.substring(0, szName.length() - 1);File folder = new File(outPathString + File.separator + szName);folder.mkdirs();} else {Log.e(TAG,outPathString + File.separator + szName);File file = new File(outPathString + File.separator + szName);if (!ists()){Log.e(TAG, "Create the file:" + outPathString + File.separator + szName);ParentFile().mkdirs();ateNewFile();}// 获取文件的输出流FileOutputStream out = new FileOutputStream(file);int len;byte[] buffer = new byte[1024];// 读取(字节)字节到缓冲区while ((len = ad(buffer)) != -1) {// 从缓冲区(0)位置写入(字节)字节out.write(buffer, 0, len);out.flush();}out.close();}}inZip.close();
}
/*** 压缩文件和文件夹** @param srcFileString 要压缩的文件或文件夹* @param zipFileString 压缩完成的Zip路径* @throws Exception* @return*/
public static void ZipFolder(String srcFileString, String zipFileString) throws Exception {//创建ZIPZipOutputStream outZip = new ZipOutputStream(new FileOutputStream(zipFileString));//创建文件File file = new File(srcFileString);//压缩Parent()+ File.separator, Name(), outZip);Log.e(TAG, "ZipFolderq: "+zipFileString );//完成和关闭outZip.finish();outZip.close();
}
/*** 压缩文件** @param folderString* @param fileString* @param zipOutputSteam* @throws Exception*/
private static void ZipFiles(String folderString, String fileString, ZipOutputStream zipOutputSteam) throws Exception {if (zipOutputSteam == null)return;File file = new File(folderString + fileString);if (file.isFile()) {ZipEntry zipEntry = new ZipEntry(fileString);FileInputStream inputStream = new FileInputStream(file);zipOutputSteam.putNextEntry(zipEntry);int len;byte[] buffer = new byte[4096];while ((len = ad(buffer)) != -1) {zipOutputSteam.write(buffer, 0, len);}zipOutputSteam.closeEntry();} else {//文件夹String fileList[] = file.list();//没有子文件和压缩if (fileList.length <= 0) {ZipEntry zipEntry = new ZipEntry(fileString + File.separator);zipOutputSteam.putNextEntry(zipEntry);zipOutputSteam.closeEntry();}//子文件和递归for (int i = 0; i < fileList.length; i++) {ZipFiles(folderString+fileString+"/", fileList[i], zipOutputSteam);}}
}
在后面Android的版本中,一般给Android app一个单独的文件夹创建由开发者使用代码创建的File,具体目录结构为/android/data/你的应用的AppID/ 然后代码一般为
File file;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {file = new ExternalFilesDir(TypeName) + File.separator ,"shapeframe"+Number);
} else {file = new ExternalStorageDirectory() + "/Android","shapeframe"+Number);
}
在androidQ即以上使用 getExternalFilesDir得到这个目录,以下使用getExternalStorageDirectory,其中TypeName中带有"File.separator"可创建二级目录。
本文发布于:2024-02-01 10:49:47,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170675578736090.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |