I am doing a simple android application which consists of compressing folder. Actually the compression process is completed and the file is saved in the defined location. But the problem is when i push the zipped file from the emulator and unzipping it manually the files are corrupted. What's the problem. Is the file become corrupted when we unzip manually?
My folder structure is given below
TestPlay1- contains two sub directories - playlist and content
the directory playlist contains a xml file
the directory content contains files such as images and videos
My code is given below
String zipFile = "/mnt/sdcard/Testplay1.zip";
byte[] buffer = new byte[1024];
FileOutputStream fos = null;
try {
fos = new FileOutputStream(zipFile);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
ZipOutputStream zos = new ZipOutputStream(fos);
updata = new ArrayList<File>();
contentpath = new File(FOLDER_PATH);
try {
if (contentpath.isDirectory()) {
File[] listFile = contentpath.listFiles();
for (int i = 0; i < listFile.length; i++) {
if (listFile[i].isDirectory()) {
File[] contfile = listFile[i].listFiles();
for (int j = 0; j < contfile.length; j++) {
updata.add(contfile[j]);
FileInputStream fis = new FileInputStream(contfile[j]);
zos.putNextEntry(new ZipEntry(contfile[j].getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
// close the InputStream
fis.close();
}
}
}
zos.close();
}
System.out.println("Testplay1 Folder contains=>" + updata);
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
I suggest you to use Zip4j: http://www.lingala.net/zip4j/
There you can just put the Folder to compress and the rest is done by the library
ZipFile zipfile = new ZipFile("/mnt/sdcard/bla.zip");
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
zipfile.addFolder("/mnt/sdcard/folderToZip", parameters);
Related
I have the following situation, where everything works perfectly on all APIs except API 30, i.e. Android 11. Namely, I first export my textual and audio files from the internal storage to the external storage, i.e. in the Downloads folder. It all works without problems on all APIs. However, when I want to import the same files from the Downloads folder into the internal storage of my app, works as it should on all APIs, but on API 30 - Android 11 it only creates the Text and Audio folder but does not import the files. It is interesting to note that mp3 files are imported, but text files are not. What do you think is the problem and is there a solution, thank you.
restore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (SDK_INT >= 23) {
if (checkPermission()) {
try {
// create Text dir
File sdcardDic = getBaseContext().getExternalFilesDir(null);
File dirDic = new File(sdcardDic.getAbsolutePath() + "/Text/");
dirDic.mkdir();
FileOutputStream dic = null;
try {
dic = new FileOutputStream(dirDic);
dic.close();
} catch (IOException e) {
e.printStackTrace();
}
// create Audio dir
File sdcardAudio = getBaseContext().getExternalFilesDir(null);
File dirAudio = new File(sdcardAudio.getAbsolutePath() + "/Audio/");
dirAudio.mkdir();
FileOutputStream audio = null;
try {
audio = new FileOutputStream(dirAudio);
audio.close();
} catch (IOException e) {
e.printStackTrace();
}
// import file from Downloads dir
File sdcard = getBaseContext().getExternalFilesDir(null);
File dir = new File(sdcard.getAbsolutePath());
appRecovery(new File(String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS))),
new File(dir.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
}
} else {
requestPermission();
}
}
}
}
});
public void appRecovery(File sourceLocation, File targetLocation)
throws IOException {
if (sourceLocation.isDirectory()) {
if (!targetLocation.exists()) {
targetLocation.mkdir();
}
String[] children = sourceLocation.list();
for (int i = 0; i < sourceLocation.listFiles().length; i++) {
appRecovery(new File(sourceLocation, children[i]),
new File(targetLocation, children[i]));
}
} else {
InputStream in = new FileInputStream(sourceLocation);
OutputStream out = new FileOutputStream(targetLocation);
// copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
I'm using this code (Android 7.0/Nougat) to unpack a zip file in external storage (including multiple folder levels inside):
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();
}
To get write access to the SD card I'm using createAccessIntent (Storage Volume) which uses DocumentFiles instead of the normal File.
I already did this to get a ZipInputStream:
InputStream inputStream = this.getContentResolver().openInputStream(myDocumentFileZip.getUri());
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream);
ZipEntry zipEntry;
...and I'm guessing that you continue like this:
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
But what do you do from there - how to you copy the files onto the SD card and still keep the folder structure like in the code above but using what Storage Volume (or Storage Access Framework) provides?
Unzip with Storage Volume:
Careful: This way it creates copies if you unzip the same .zip file multiple times, while my original code in the first post (which you can't use for an SD card) doesn't but instead overwrites automatically!
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();
}
Edit: Important: java.util.zip doesn't set the size or compressedSize (will return "-1"), that's why this code will only create files with a size of 0B with zip files that were created by the library - zip files that were created by hand (e.g. with WinRar) work fine. To fix it, replace
while (((len = zis.read(buffer, 0, 10000)) > 0) && (totlen < zipfilesize)) {
with
while (((len = zis.read(buffer, 0, 10000)) > 0)) {
It's possible to do this because:
the call to ZipInputStream.getNextEntry() positions the InputStream at the start of the entry and therefore supplying the ZipInputStream is the equivalent of supplying a ZipEntry's InputStream.
Source: https://stackoverflow.com/a/3233600/2016165
The disadvantages with this (in comparison to my non-StorageVolume version) are that you a) can't get the total amount of files in the zip and b) also can't get the (total) size of the files, which means that you can't set the progress bar in an "Unzipping..." dialog unless you iterate through all the zip entries first to count them.
I have a created a directory with some images stored in it. Now, to zip it as a single .zip file, I used the following code :
private static void zipDir(String zipFileName, String dir) throws Exception {
File dirObj = new File(dir);
ZipOutputStream out = new ZipOutputStream(newFileOutputStream(zipFileName));
addDir(dirObj, out);
out.close();
}
static void addDir(File dirObj, ZipOutputStream out) throws IOException {
File[] files = dirObj.listFiles();
byte[] tmpBuf = new byte[1024];
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
addDir(files[i], out);
continue;
}
FileInputStream in = new FileInputStream(files[i].getAbsolutePath());
System.out.println(" Adding: " + files[i].getAbsolutePath());
out.putNextEntry(new ZipEntry(files[i].getAbsolutePath()));
int len;
while ((len = in.read(tmpBuf)) > 0) {
out.write(tmpBuf, 0, len);
}
out.closeEntry();
in.close();
}
}
I obtained this code from the following source : http://www.java2s.com/Code/Java/File-Input-Output/Makingazipfileofdirectoryincludingitssubdirectoriesrecursively.htm
When I run this code, in the specified directory, a .zip file is created with the specified name but when I try to open it using any software(winzip, etc) on Android or on PC, it displays the error message that : This file is corrupt or not a valid zip file"
Any help would be appreciated.
I was thinking about deleting the question. But it stands for a rather interesting read. While creating the .zip file, I had specified the same directory as the one which I wanted to compress. This results in an infinite loop. Changing the .zip directory solves the issue.
I mean like this:
private static void zipDir(String zipFileName, String dir) throws Exception {
List<String> files = buildFileList(dir, "");
ZipOutputStream out = new ZipOutputStream(newFileOutputStream(zipFileName));
zipFiles(files, out);
out.close();
}
static List<String> buildFileList(String path, String filter) {
List<String> lstFile = new ArrayList<String>();
File[] files = new File(path).listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
if (filter.length() == 0 || f.getName().matches(filter))
lstFile.add(f.getAbsolutePath());
} else if (f.isDirectory() && f.getPath().indexOf("/.") == -1)
lstFile.addAll(getFilePaths(f.getAbsolutePath(), filter));
}
}
return lstFile;
}
static void zipFiles(List<String> files, ZipOutputStream out) throws IOException {
byte[] tmpBuf = new byte[1024];
for (String file : files) {
if (new File(file).isDirectory()) {
continue;
}
FileInputStream in = new FileInputStream(file);
System.out.println(" Adding: " + file);
out.putNextEntry(new ZipEntry(file));
int len;
while ((len = in.read(tmpBuf)) > 0) {
out.write(tmpBuf, 0, len);
}
out.closeEntry();
in.close();
}
}
Please, suggest me the best way of copying a folder from assets to /data/data/my_app_pkg/files.
The folder from assets (www) contains files and subfolders. which I want to completely copy to the files/ of my internal app path mentioned.
I am successfully able to copy a file from assets to internal app files/ path, but unable to do the same in case of copying folder, even assetmanager.list isn't helping me out, as it is copying only the files, but not the directories / subfolders.
Please kindly suggest me the better way to do what I want
Hope use full to you below code:-
Copy files from a folder of SD card into another folder of SD card
Assets
AssetManager am = con.getAssets("folder/file_name.xml");
public static void copyDirectoryOneLocationToAnotherLocation(File sourceLocation, File targetLocation)
throws IOException {
if (sourceLocation.isDirectory()) {
if (!targetLocation.exists()) {
targetLocation.mkdir();
}
String[] children = sourceLocation.list();
for (int i = 0; i < sourceLocation.listFiles().length; i++) {
copyDirectoryOneLocationToAnotherLocation(new File(sourceLocation, children[i]),
new File(targetLocation, children[i]));
}
} else {
InputStream in = new FileInputStream(sourceLocation);
OutputStream out = new FileOutputStream(targetLocation);
// Copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
Hope this will help
private void getAssetAppFolder(String dir) throws Exception{
{
File f = new File(sdcardlocation + "/" + dir);
if (!f.exists() || !f.isDirectory())
f.mkdirs();
}
AssetManager am=getAssets();
String [] aplist=am.list(dir);
for(String strf:aplist){
try{
InputStream is=am.open(dir+"/"+strf);
copyToDisk(dir,strf,is);
}catch(Exception ex){
getAssetAppFolder(dir+"/"+strf);
}
}
}
public void copyToDisk(String dir,String name,InputStream is) throws IOException{
int size;
byte[] buffer = new byte[2048];
FileOutputStream fout = new FileOutputStream(sdcardlocation +"/"+dir+"/" +name);
BufferedOutputStream bufferOut = new BufferedOutputStream(fout, buffer.length);
while ((size = is.read(buffer, 0, buffer.length)) != -1) {
bufferOut.write(buffer, 0, size);
}
bufferOut.flush();
bufferOut.close();
is.close();
fout.close();
}
i'm facing a problem with unzipping files in Android. Here is the code snippet:
public void unzip() {
try {
FileInputStream fin = new FileInputStream(_zipFile);
BufferedInputStream in = new BufferedInputStream(fin);
ZipInputStream zin = new ZipInputStream(in);
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 out = new BufferedOutputStream(fout);
byte[] buffer = new byte[1024];
int length;
while ((length = zin.read(buffer,0,1024)) >= 0) {
out.write(buffer,0,length);
}
/* while ((length = zin.read(buffer))>0) {
out.write(buffer, 0, length);
}*/
/*for (int c = zin.read(); c != -1; c = zin.read()) {
fout.write(c);
}*/
zin.closeEntry();
fout.close();
}
}
zin.close();
} catch(Exception e) {
Log.e("Decompress", "unzip", e);
}
}
Smaller files (smaller than 10kB) are unzipped like empty - size 0 (html files, .jpg). Other files are ok. If I use this same code, but without buffers all the files are ok - ofcourse, unzipping without buffers is out of the question since it runs too long. Files are stored on SD card on real device. I have already tried setting smaller buffer size ( even new byte[2]). Thanks in advance...
Try this code instead,
public void doUnzip(String inputZipFile, String destinationDirectory)
throws IOException {
int BUFFER = 2048;
List zipFiles = new ArrayList();
File sourceZipFile = new File(inputZip);
File unzipDestinationDirectory = new File(destinationDirectory);
unzipDestinationDirectory.mkdir();
ZipFile zipFile;
// Open Zip file for reading
zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ);
// Create an enumeration of the entries in the zip file
Enumeration zipFileEntries = zipFile.entries();
// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(unzipDestinationDirectory, currentEntry);
// destFile = new File(unzipDestinationDirectory, destFile.getName());
if (currentEntry.endsWith(".zip")) {
zipFiles.add(destFile.getAbsolutePath());
}
// grab file's parent directory structure
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
try {
// extract file if not a directory
if (!entry.isDirectory()) {
BufferedInputStream is =
new BufferedInputStream(zipFile.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest =
new BufferedOutputStream(fos, BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
zipFile.close();
for (Iterator iter = zipFiles.iterator(); iter.hasNext();) {
String zipName = (String)iter.next();
doUnzip(
zipName,
destinationDirectory +
File.separatorChar +
zipName.substring(0,zipName.lastIndexOf(".zip"))
);
}
}