I am trying to unzip some files from a zip file to an unzipped directory with the same file structure as the zipped file, but am having difficulty with the getNextEntry() method. It seems to be returning only the files in the zipped file and not the folders which is causing a FileNotFoundException when I try to create a file in a directory that doesn't exist.
For example the first level of my zip file is like the following:
Folder 1
file2.txt
Folder 2
Folder 3
file.txt
When I call getNextEntry() the first thing returned is file.txt, the second thing returned is Folder 1/file2.txt. Even the nested folders are being ignored. This was previously working, however, I'm not sure what I did to break it.
The file I'm passing in is a zipped file located in internal storage. Any help will be much appreciated!
public boolean unZipAndEncrypt(File file) {
boolean isSuccess = false;
ZipInputStream zin = null;
try {
ZipFile zipFile = new ZipFile(file);
FileInputStream fin = new FileInputStream(file);
zin = new ZipInputStream(fin);
ZipEntry ze;
File contentDir = new File(bookDirectory, contentId);
while ((ze = zin.getNextEntry()) != null) {
String name = ze.getName();
if (ze.isDirectory()) {
File dir = new File(contentDir, name);
dir.mkdirs();
continue;
}
FileModel fileModel = new FileModel(zipFile.getInputStream(ze), name);
if (!ze.getName().contains("cp_index")) {
fileModel = encryptor.encrypt(fileModel);
}
File toWrite = new File(contentDir, fileModel.getFullPathName());
toWrite.createNewFile();
OutputStream fout = new FileOutputStream(toWrite);
try {
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fileModel.getInputStream().read(buffer)) != -1) {
fout.write(buffer, 0, len);
}
} finally {
fileModel.close();
zin.closeEntry();
fout.close();
}
}
isSuccess = true;
} catch (FileNotFoundException e) {
Log.e(TAG, "", e);
} catch (IOException e) {
Log.e(TAG, "", e);
} finally {
file.delete();
try {
zin.close();
} catch (IOException e) {
Log.e(TAG, "", e);
} catch (NullPointerException e) {
Log.e(TAG, "", e);
}
}
return isSuccess;
}
You could create the directory before creating the new file:
toWrite.getParentFile().mkdirs(); // do before createNewFile()
Related
I want to download all the files from Azure blob storage, create a zip file out of these files and upload the zip file back to the blob storage.
As the file size can be very large, I dont want to max out the memory.
Also this operation needs to be very FAST.
JAVA SDK - azure-storage-blob 12.8.0
EDIT : Code written so far. Not sure how to proceed further with uploading pipedinputstream data parallely.
String zipFileName = formFileName(exportRequest, requestId);
final PipedOutputStream pipedOutputStream = new PipedOutputStream();
final PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
AzureObjectStoreService objectStoreService =managedObjectStoreUtils.getObjectStoreService();
if (filesToZip.size() > 0) {
System.out.println("Files to zip "+ filesToZip.size());
CompletableFuture<Boolean> zipCreationFuture = CompletableFuture.runAsync(() -> {
LoggerHelper.logInfo(logger, "Inside createZIP file async function");
ZipOutputStream zipOutputStream = new ZipOutputStream(pipedOutputStream);
try {
for (String fileName : filesToZip) {
try {
BlobClient blobClient = objectStoreService.getBlobContainerClient().getBlobClient(fileName);
LoggerHelper.logInfo(logger, "Adding zipEntry for file : " + fileName);
final ZipEntry zipEntry = new ZipEntry(fileName);
zipOutputStream.putNextEntry(zipEntry);
byte[] buffer;
ByteArrayOutputStream output = new ByteArrayOutputStream();
buffer= output.toByteArray();
blobClient.getBlockBlobClient().download(output);
int len;
while ((len = buffer.length) > 0) {
zipOutputStream.write(buffer, 0, len);
}
zipOutputStream.closeEntry();
} catch (SdkClientException e) {
LoggerHelper.logExceptionWithMessage(logger, this.getClass().getName(), (Exception) e);
LoggerHelper.logError(logger, "Failed while getting s3 object");
}
}
zipOutputStream.finish();
} catch (IOException ex) {
LoggerHelper.logExceptionWithMessage(logger, this.getClass().getName(), (Exception) ex);
LoggerHelper.logError(logger, "Creating zip file failed");
} finally {
try {
zipOutputStream.close();
} catch (IOException e) {
LoggerHelper.logExceptionWithMessage(logger, this.getClass().getName(), (Exception) e);
LoggerHelper.logError(logger, "Failed to close the zip output stream");
}
}
LoggerHelper.logInfo(logger, "Completed createZIP file async function");
// return true;
}).handle((o, exception) -> {
LoggerHelper.logExceptionWithMessage(logger, this.getClass().getName(), (Exception) exception);
LoggerHelper.logError(logger, "Creating zip file failed");
return null;
});
Was able to do it this way. Please let me know if anyone has a better approach.
CompletableFuture.runAsync(() -> {
BlobClient blobClient = objectStoreService.getBlobContainerClient().getBlobClient(zipFileName);
BlobOutputStream blobOutputStream = blobClient.getBlockBlobClient().getBlobOutputStream();
try {
int nextData= pipedInputStream.read();
while (nextData!=-1) {
blobOutputStream.write(nextData);
nextData = pipedInputStream.read();
}blobOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
create and download zip file by adding list of text files. with out creating the file in local server, it should be download at client side direct,
Here i added a code snippet, it was creating in local server, but i dont want that, it should create and download at client side instant. Please help me in this way..
#GetMapping("/download/rawdata")
public void downloadRawdata(#RequestParam("date") String date){
log.info("date : "+date);
List<Rawdata> rawdatas = rawdataRepoisotry.findRawdataByDate(date);
log.info("size of rawdata : "+rawdatas.size());
List<File> files = new ArrayList<File>();
int i = 1;
for(Rawdata rawdata : rawdatas){
log.info("rawdata : "+ rawdata.getRawdata());
File file = new File(i+".txt");
try (Writer writer = new BufferedWriter(new FileWriter(file))) {
String contents = rawdata.getRawdata();
writer.write(contents);
files.add(file);
} catch (IOException e) {
e.printStackTrace();
}
i++;
}
try {
zipFile(files, new File(date+".zip"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed while creating Zip file");
}
}
public FileOutputStream zipFile(final List<File> files, final File targetZipFile) throws IOException {
try {
FileOutputStream fos = new FileOutputStream(targetZipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
byte[] buffer = new byte[128];
for(File currentFile : files){
if (!currentFile.isDirectory()) {
ZipEntry entry = new ZipEntry(currentFile.getName());
FileInputStream fis = new FileInputStream(currentFile);
zos.putNextEntry(entry);
int read = 0;
while ((read = fis.read(buffer)) != -1) {
zos.write(buffer, 0, read);
}
zos.closeEntry();
fis.close();
}
}
zos.close();
fos.close();
return fos;
} catch (FileNotFoundException e) {
System.out.println("File not found : " + e);
throw new FileNotFoundException();
}
}
Here is an example using FileSystemResource.
What has been modified is (see the numbers in the commented code ) :
1) Declare that the response will be of type application/octet-stream
2) #ResponseBody
Annotation that indicates a method return value should be bound to the
web response body
3) Declare that the method returns a FileSystemResource body
4) Return the FileSystemResource entity based on your created zip file
Note that this will still create the file on the server side first, but you may want to use File.createTempFile and File.deleteOnExit.
#GetMapping("/download/rawdata", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)//1
#ResponseBody //2
public ResponseEntity<FileSystemResource> downloadRawdata(#RequestParam("date") String date){ //3
log.info("date : "+date);
List<Rawdata> rawdatas = rawdataRepoisotry.findRawdataByDate(date);
log.info("size of rawdata : "+rawdatas.size());
List<File> files = new ArrayList<File>();
int i = 1;
for(Rawdata rawdata : rawdatas){
log.info("rawdata : "+ rawdata.getRawdata());
File file = new File(i+".txt");
try (Writer writer = new BufferedWriter(new FileWriter(file))) {
String contents = rawdata.getRawdata();
writer.write(contents);
files.add(file);
} catch (IOException e) {
e.printStackTrace();
}
i++;
}
try {
File resultFile = new File(date+".zip");
zipFile(files, resultFile);
return new ResponseEntity<>(new FileSystemResource(resultFile), HttpStatus.OK); //4
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed while creating Zip file");
}
}
I have written code that should be saved file in the local directory, create zip of that file, send email and delete both files (original and zip), So this is my code:
Method wich send email
public void sendEmail(Properties emailProperties, InputStream inputStream, HttpServletRequest request) throws UnsupportedEncodingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
try {
mimeMessageHelper.setFrom(from, personal);
} catch (UnsupportedEncodingException e) {
LOGGER.error(e.getMessage());
throw new SequelException(e.getMessage());
}
mimeMessageHelper.setTo(recipients);
mimeMessageHelper.setSubject(emailProperties.getProperty(PARAM_TITLE));
String message = emailProperties.getProperty(PARAM_EMLMSG);
mimeMessageHelper.setText(message);
InputStreamSource inputStreamSource = null;
if (inputStream != null) {
inputStreamSource = new ByteArrayResource(IOUtils.toByteArray(inputStream));
}
String compressType = COMPRESS_TYPE_ZIP;
String fileName = getAttachFilenameExtension(object, format);
Path filePath = Paths.get(StrUtils.getProperty("temp.email.files.path") + "\\" + fileName);
tempFile = saveTempFile(inputStreamSource.getInputStream(), filePath);
if (tempFile.length() > 0) {
inputStreamSource = compressFile(tempFile, filePath.toString(), compressType);
fileName = StringUtils.substring(fileName, 0, StringUtils.lastIndexOf(fileName, ".")+1) + compressType;
}
mimeMessageHelper.addAttachment(fileName, inputStreamSource);
mailSender.send(mimeMessage);
} catch (MessagingException | IOException e) {
LOGGER.error(e.getMessage());
throw new SequelException(e.getMessage());
} finally {
List<File> files = (List<File>) FileUtils.listFiles(tempFile.getParentFile(), new WildcardFileFilter(
FilenameUtils.removeExtension(tempFile.getName()) + "*"), null);
for (File file : files) {
try {
FileUtils.forceDelete(file);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}
}
Save file in directory:
private File saveTempFile(InputStream inputStream, Path filePath) throws IOException {
Files.deleteIfExists(filePath);
Files.copy(inputStream, filePath);
return new File(filePath.toString());
}
Compress file:
private InputStreamSource compressFile(File file, String filePath, String compressType) throws IOException {
InputStream is = ZipFile(file, filePath);
InputStreamSource inputStreamSource = new ByteArrayResource(IOUtils.toByteArray(is));
return inputStreamSource;
}
public InputStream ZipFile(File file, String filePath) {
String zipArchiveFileName = StringUtils.substring(filePath, 0, filePath.lastIndexOf(".") + 1) + COMPRESS_TYPE_ZIP;
try (ZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(new File(zipArchiveFileName));) {
ZipArchiveEntry entry = new ZipArchiveEntry(StringUtils.overlay(file.getName(), "",
StringUtils.lastIndexOf(file.getName(), "_"), StringUtils.lastIndexOf(file.getName(), ".")));
zipOutput.putArchiveEntry(entry);
try (FileInputStream in = new FileInputStream(file);) {
byte[] b = new byte[1024];
int count = 0;
while ((count = in.read(b)) > 0) {
zipOutput.write(b, 0, count);
}
zipOutput.closeArchiveEntry();
}
InputStream is = new FileInputStream(zipArchiveFileName);
return is;
} catch (IOException e) {
LOGGER.error("An error occurred while trying to compress file to zip", e);
throw new SequelException(e.getMessage());
}
}
So the problem is when I try to delete files but zip file does not delete.
I am using Apache commons compress for zipping.
Can you help what's wrong?
For me this code is working perfectly. After compressing you may be trying to delete it without the extension(for eg .7z here).
public static void main(String[] args) {
File file = new File("C:\\Users\\kh1784\\Desktop\\Remote.7z");
file.delete();
if(!file.exists())
System.out.println("Sucessfully deleted the file");
}
Output:-
Sucessfully deleted the file
My android application is very simply extract zip.
I want to create a folder with the FileName erase the extension (.zip) in the zip file.
And i'm succeeded.
However, the exception in some devices.
device name : KM-S300
os version : 2.3.4
source:
private void extractZip (File file) throws UTFDataFormatException {
FileInputStream fis = null;
FileOutputStream fos = null;
ZipInputStream zis = null;
ZipEntry ze = null;
byte[] data = new byte[1024];
int offset = 0;
String rootName = file.getAbsolutePath();
rootName = rootName.substring(0, rootName.lastIndexOf("."));
String rootFileName = rootName.substring(rootName.lastIndexOf("/") + 1);
File root = new File(rootName);
root.mkdirs();
try {
fis = new FileInputStream(file);
zis = new ZipInputStream(fis);
while (( ze = zis.getNextEntry() ) != null) {
try {
File f = new File(root, ze.getName());
if (!f.isDirectory()) {
f.getParentFile().mkdirs();
fos = new FileOutputStream(f); // <<-- ERROR
while (( offset = zis.read(data) ) != -1) {
fos.write(data, 0, offset);
}
}
} finally {
try {
fos.close();
} catch (Exception e) {}
}
}
file.delete();
}catch (UTFDataFormatException e){
throw e;
}catch (Exception e) {
e.printStackTrace();
} finally {
try {
zis.close();
} catch (Exception e) {}
try {
fis.close();
} catch (Exception e) {}
}
}
I can't understand Exception
java.io.FileNotFoundException: /mnt/sdcard/test/marker/Explosion/failed/0.png (No such file or directory)
at org.apache.harmony.luni.platform.OSFileSystem.open(Native Method)
at dalvik.system.BlockGuard$WrappedFileSystem.open(BlockGuard.java:232)
at java.io.FileOutputStream.<init>(FileOutputStream.java:94)
at java.io.FileOutputStream.<init>(FileOutputStream.java:66)
at com.sample.MainActivity.extractZip(MainActivity.java:507)
Made to the parent folder of the File prior to creating the FileOutputStream
Why did exception by application?
You're only creating the parent directory if the new file doesn't exist or isn't a directory. It's not a sensible test. You should create it if the parent directory doesn't exist.
I'm trying to unzip a File (30 Mb) programmatically, this is my script
public void unzip() {
dirChecker(location);
try {
FileInputStream fin = new FileInputStream(zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
Log.v("Decompress", "Unzipping " + location+ze.getName());
//create dir if required while unzipping
if (ze.isDirectory()) {
dirChecker(ze.getName());
} else {
FileOutputStream fout = new FileOutputStream(location + ze.getName());
IoUtils.copyStream(zin, fout);
zin.closeEntry();
fout.close();
}
}
zin.close();
} catch (Exception e) {
System.out.println(e);
}
}
private void dirChecker(String dir) {
File f = new File(location + dir);
if (!f.isDirectory()) {
f.mkdirs();
}
}
the unzipping goes well, until the 24th file in the zip, the application hangs whithout giving any error, simply freeze in the line:
IoUtils.copyStream(zin, fout);
no log, no exception trown, nothing... i discovered the right line putting a break point after the try and manually cicling until the 24th file arrive (it's an 1.1mb jpg, i had no trouble extracting with winzip)
any hint?