Как распаковать файл с помощью тома хранилища (/ StorageAccessFramework)? - PullRequest
0 голосов
/ 14 мая 2018

Я использую этот код (Android 7.0 / Nougat) для распаковки zip-файла во внешнее хранилище (включая несколько уровней папок внутри):

try {
    ZipFile zip = new ZipFile(zippath);
    Enumeration enu = zip.entries();

    while(enu.hasMoreElements()) {
        ZipEntry zipEntry = (ZipEntry) enu.nextElement();
        BufferedInputStream bis = null;
        String fileName = null;

        try {
            fileName = zipEntry.getName();
            fileName = fileName.replace("\\",File.separator).replace("/",File.separator);
            int p = fileName.lastIndexOf(File.separator);

            if(p>=0) {
                File fd=new File(folderpath+File.separator+fileName.substring(0,p));
                fd.mkdirs();
            }

            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(folderpath+File.separator+fileName));
            bis = new BufferedInputStream(zip.getInputStream(zipEntry));
            byte[] buffer = new byte[10000];
            int len = 0;

            while ((len = bis.read(buffer, 0, 10000)) > 0) {
                bos.write(buffer, 0, len);
            }

            bis.close();
            bos.close();
        } catch (IOException e1) {
            e1.printStackTrace();
            return;
        }
    }
} catch (IOException e2) {
    e2.printStackTrace();
}

Чтобы получить доступ для записи на SD-карту, я использую createAccessIntent (Объем хранения), который использует DocumentFile s вместо обычного File.

Я уже сделал это, чтобы получить ZipInputStream:

InputStream inputStream = this.getContentResolver().openInputStream(myDocumentFileZip.getUri());
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream);
ZipEntry zipEntry;

... и я предполагаю, что вы продолжите так:

while ((zipEntry = zipInputStream.getNextEntry()) != null) {

Но что вы делаете оттуда - как вы копируете файлы на SD-карту и сохраняете структуру папок, как в приведенном выше коде, но используете то, что обеспечивает Storage Volume (или Storage Access Framework)?

1 Ответ

0 голосов
/ 25 мая 2018

Распаковать с томом хранилища:

Осторожно: Таким образом, он создает копии, если вы разархивируете один и тот же файл .zip несколько раз, в то время как мой оригинальный код в первом посте (который вы не можете использовать для SDкарточка) не делает, но вместо этого автоматически перезаписывает!

try {
    InputStream is = getContentResolver().openInputStream(myZip.getUri());
    BufferedInputStream bis = new BufferedInputStream(is);
    ZipInputStream zis = new ZipInputStream(bis);
    ZipEntry zipEntry;

    while ((zipEntry = zis.getNextEntry()) != null) {
        String fileName = null; 

        try {
            fileName = zipEntry.getName();        
            fileName = fileName.replace("\\",File.separator).replace("/",File.separator);
            int p=fileName.lastIndexOf(File.separator);        
            DocumentFile destFolder = myDestFolder; //DocumentFile of the destination folder
            String destName = fileName;

            if (p>=0) {
                String[] split = fileName.split(File.separator);

                //If the .zip file contains multiple folder levels, this is where you  
                //have to check and then create them, e.g. for 3 levels:
                if(split.length==1) {
                    destFolder = myFolder;
                    destName = filename;
                } else if(split.length==2) {
                    if(mySubFolder==null) {
                        mySubFolder = myFolder.createDirectory(split[0]);
                    }

                    destFolder = mySubFolder;
                    destName = split[1];
                } else if(split.length==3) {
                    if(mySubFolder==null) {
                        mySubFolder = myFolder.createDirectory(split[0]);
                    }
                    if(mySubSubFolder==null) {
                        mySubSubFolder = mySubFolder.createDirectory(split[1]);
                    }

                    destFolder = mySubSubFolder;
                    destName = split[2];
                }
            }

            DocumentFile df = null;

            //Now you have to tell it what file extensions ("MIME" type) you want to use, e.g.:
            if(destName.endsWith(".txt")) {
                df = destFolder.createFile("text/plain",destName.substring(0,destName.length()-4));
            } else if(destName.endsWith(".jpg")) {
                df = destFolder.createFile("image/jpeg",destName.substring(0,destName.length()-4));
            }

            OutputStream out = getContentResolver().openOutputStream(df.getUri());
            BufferedOutputStream bos = new BufferedOutputStream(out);
            long zipfilesize = zipEntry.getSize();

            byte[] buffer = new byte[10000];
            int len = 0;
            int totlen = 0;

            while (((len = zis.read(buffer, 0, 10000)) > 0) && (totlen < zipfilesize)) {
                bos.write(buffer, 0, len);
                totlen += len;
            }

            bos.close();
        } catch (IOException e1) {
            e1.printStackTrace();
            return;
        }
    }

    is.close();
    bis.close();
    zis.close();
} catch (IOException e2) {
    e2.printStackTrace();
}

Редактировать: Важно : java.util.zip не устанавливает size или compressedSize (вернет "-1"), поэтому этот код будет создавать только файлы размером 0B с zip-файлами, которые были созданы библиотекой - zip-файлы, созданные вручную (например, с помощью WinRar), работают нормально.Чтобы исправить это, замените

while (((len = zis.read(buffer, 0, 10000)) > 0) && (totlen < zipfilesize)) {

на

while (((len = zis.read(buffer, 0, 10000)) > 0)) {

Это можно сделать, потому что:

вызов ZipInputStream.getNextEntry () позиционируетInputStream в начале записи и, следовательно, предоставление ZipInputStream является эквивалентом предоставления InputStream ZipEntry.

Source: https://stackoverflow.com/a/3233600/2016165

Недостатки этого (по сравнению с моимверсия не StorageVolume): а) вы не можете получить общее количество файлов в zip и б) также не можете получить (общий) размер файлов, а это означает, что вы не можете установить индикатор выполненияв диалоговом окне «Распаковка ...», если сначала вы не перебираете все записи zip для их подсчета.

...