I am trying to unzip a file from the internet using the following code. On one of the files("uq.class"), after it has been unzipped from the online source, is missing about 2kb of file size(the original file is 10,084, unzipped I get 8,261). All the other files seem to be completely fine, and when I copy the uq.class file from the zip and place it in manually, it functions perfectly. Can anyone explain whats going on and provide a fix? Below is the unzipping portions of the code.
public static File unpackArchive(URL url, File targetDir) throws IOException {
if (!targetDir.exists()) {
targetDir.mkdirs();
}
InputStream in = new BufferedInputStream(url.openStream(), 2048);
// make sure we get the actual file
File zip = File.createTempFile("arc", ".zip", targetDir);
OutputStream out = new BufferedOutputStream(new FileOutputStream(zip),2048);
copyInputStream(in, out);
out.close();
return unpackArchive(zip, targetDir);
}
public static File unpackArchive(File theFile, File targetDir) throws IOException {
if (!theFile.exists()) {
throw new IOException(theFile.getAbsolutePath() + " does not exist");
}
if (!buildDirectory(targetDir)) {
throw new IOException("Could not create directory: " + targetDir);
}
ZipFile zipFile = new ZipFile(theFile);
for (Enumeration entries = zipFile.entries(); entries.hasMoreElements();) {
ZipEntry entry = (ZipEntry) entries.nextElement();
File file = new File(targetDir, File.separator + entry.getName());
if (!buildDirectory(file.getParentFile())) {
throw new IOException("Could not create directory: " + file.getParentFile());
}
if (!entry.isDirectory()) {
copyInputStream(zipFile.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(file),2048));
} else {
if (!buildDirectory(file)) {
throw new IOException("Could not create directory: " + file);
}
}
}
zipFile.close();
theFile.delete();
return theFile;
}
public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len >= 0) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
in.close();
out.close();
}
public static boolean buildDirectory(File file) {
return file.exists() || file.mkdirs();
}
Cannot directly see anything wrong with the code at first sight. What I would recommend you doing however is closing your streams more safely. In your current implementation you close the in and out streams at the same time, close statements can cause exceptions as can read and write statements! If any one of those fails, your files will be left open and in time your application will run out of file descriptors. You're better off doing the closing in a finally statement, that way you're sure they get closed.
I don't know why I cant sign in, but I figured out the issue. I did the whole cart before the horse thing. I extracted the proper file, then extracted the old file over it, so I kept re-integrating the older file. 5 hours of programming out the window. Remember, kiddies, proper programming architecture saves you A TON of headaches.
Related
I was trying to extract the ZIP file from my Linux, I'm able to extract it, but the expected output is failing/wrong. The extract file suddenly has no files inside and the folder extracted has .zip25 extension. I searched on this, and there is saying that it is corrupted. However, I don't think it is corrupted because I am able to open and extract the zip files perfectly in local (Windows directory).
Example:
Zip file: FolderZip.zip
After extract: FolderZip.zip25 (Note: This is already extracted but still has .zip25 extension, also the files inside are missing).
Below is my code, I've worked on this for almost a month, but still can't figure it out. Can someone help me to figure out what did I do wrong?
public void unZipFolder(String zipFile, String outputFolder){
byte[] buffer = new byte[1024];
System.out.println("ZipFileLocation: " + zipFile);
LOG.info(" ZipFileLocation: " + zipFile);
File folder = new File(outputFolder);
if(!folder.exists())folder.mkdirs();
try{
FileInputStream fis = new FileInputStream(zipFile);
ZipInputStream zis = new ZipInputStream(fis);
ZipEntry ze = zis.getNextEntry();
while(ze != null) {
new File(folder.getParent()).mkdirs();
FileOutputStream fos = new FileOutputStream(folder);
File newFile = new File(outputFolder + FilenameUtils.indexOfLastSeparator(ze.getName()));
if (ze.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}else if(ze.isDirectory()){
newFile.mkdirs();
continue;
}else{
int len;
while ((len = zis.read(buffer)) >= 0) {
fos.write(buffer, 0, len);
}
System.out.println("File Unzip: " + newFile);
LOG.info(" File Unzip: " + newFile);
newFile.mkdirs();
fos.close();
zis.closeEntry();
ze = zis.getNextEntry();
}
}
boolean result = Files.deleteIfExists(Paths.get(zipFile));
if (result) {
System.out.println("ZipFile is deleted....");
} else {
System.out.println("Unable to delete the file.....");
}
}
zis.closeEntry();
zis.close();
fis.close();
}catch(IOException ex){
ex.printStackTrace();
}
}
I'd love to be able to tell you exactly what's wrong with your code, but FileOutputStream fos = new FileOutputStream(folder); throws an exception because, well, folder is, a directory, so you can't write to it.
I'm also scratching my head over what your expecting new File(folder.getParent()).mkdirs(); to do.
I basically threw out your code and started again with...
public void unZipFolder(File zipFile, File outputFolder) throws IOException {
byte[] buffer = new byte[1024];
System.out.println("ZipFileLocation: " + zipFile);
System.out.println("outputFolder = " + outputFolder);
if (!outputFolder.exists() && !outputFolder.mkdirs()) {
throw new IOException("Unable to create output folder: " + outputFolder);
} else if (outputFolder.exists() && !outputFolder.isDirectory()) {
throw new IOException("Output is not a directory: " + outputFolder);
}
try (ZipFile zipper = new ZipFile(zipFile)) {
Enumeration<? extends ZipEntry> entries = zipper.entries();
while (entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement();
File destination = new File(outputFolder, ze.getName());
if (ze.isDirectory()) {
if (!destination.exists() && !destination.mkdirs()) {
throw new IOException("Could not create directory: " + destination);
}
} else {
System.out.println("Writing " + destination);
try (InputStream is = zipper.getInputStream(ze); FileOutputStream fos = new FileOutputStream(destination)) {
// You could use is.transferTo(fos) here but I'm a grump old coder
byte[] bytes = new byte[1024 * 4];
int bytesRead = -1;
while ((bytesRead = is.read(bytes)) != -1) {
fos.write(bytes, 0, bytesRead);
}
}
}
}
}
}
Now, what's important to know about this is, it expects the directory contents of the zip files to be relative (ie no root directory information). If your zip file does contain root directory information (ie C:/... or /...), then you're going to need to clean that up yourself.
Now, if you have trouble with this, I would suggest commenting out the "extraction" portion of the code and placing in more System.out.println statements
transferTo
After reading through the code for transferTo, it's basically doing the same thing that the code example above is doing - so, if you wanted to reduce the code complexity (and reduce the risk of possible bugs), you could use it - been some what old school, I'd probably still do it the "old way" in order to provide support for progress monitoring of some kind - but that's beyond the scope of the question.
"Security issues"
This ones a little harder to tie down, as no solution is 100% safe.
I modified the above code to use something like...
Path parent = outputFolder.toPath().toAbsolutePath();
String name = "../" + ze.getName();
Path child = parent.resolveSibling(new File(outputFolder, name).toPath());
And this ended up throwing a NoSuchFileException, so, at least you could "fail fast", assuming that's what you want.
You might also consider removing .., leading / or leading path specifications in an attempt to make the path "relative", but that could become complicated as something like somePath/../file could still be valid within your use case.
During the execution of my program it creates a directory which contains two sub-directories/two folders. Into one of these folders I need to copy a Jar-File. My programm resembles an installation routine. The copying of the Jar file is not the problem here, but the permissions of the created directories.
I tried to set the permissions of the directories (before actually creating them with the mkdirs() method) with File.setWritable(true, false) and also with the .setExecutable and .setReadable methods, but the access to the sub-directories is still denied.
Here's an excerpt of my code for the creation of one of the two sub-directories:
folderfile = new File("my/path/to/directory");
folderfile.setExecutable(true, false);
folderfile.setReadable(true, false);
folderfile.setWritable(true, false);
result = folderfile.mkdirs();
if (result) {
System.out.println("Folder created.");
}else {
JOptionPane.showMessageDialog(chooser, "Error");
}
File source = new File("src/config/TheJar.jar");
File destination = folderfile;
copyJar(source, destination);
And my "copyJar" method:
private void copyJar(File source, File dest) throws IOException {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(source);
os = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer))>0) {
os.write(buffer, 0, length);
}
} catch (Exception e) {
e.printStackTrace();
}
is.close();
os.close();
}
At os = new FileOutputStream(dest); the debugger throws a FileNotFoundException with the description that the access to the directory has been denied.
Does anyone have an idea what I am doing wrong or have a better solution for setting the permissions via Java? Thanks in advance!
A similar question was asked there are several years.
A possible solution for Java 7 and Unix system is available here : How do i programmatically change file permissions?
Or, below the best response, a example with JNA.
I hope that that will help you !
I solved the problem. In the end it was much easier to solve than expected.
The main problem was not the permission issue but the FileNotFoundException. The file that is assigned to the OutputStream is not really a file, but just a directory so that the Stream can't find it. You have to create the file before initializing the OutputStream and after that you copy your source file into the newly created file. The code:
private void copyJar(File source, File dest) throws IOException {
InputStream is = null;
File dest2 = new File(dest+"/TheJar.jar");
dest2.createNewFile();
OutputStream os = null;
try {
is = new FileInputStream(source);
os = new FileOutputStream(dest2);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer))>0) {
os.write(buffer, 0, length);
}
} catch (Exception e) {
e.printStackTrace();
}
is.close();
os.close();
}
I'm trying to write to an external txt (or csv) file for Android. I can run an app, close it, and run it again, and readData() will read back to my log what I've stored. However, the dirFile (file directory) appears nowhere within my Android files (even if I connect it to a computer and search).
Something interesting, though: if I clear my log (similar to a list of print statements shown within Eclipse) and disconnect my phone from my computer, then reconnect it, the log reappears with everything I've ever written to my file (even if I later overwrote it)...yet the app isn't even running!
Here is my code. Please help me understand why I cannot find my file!
(Note: I've tried appending a "myFile.txt" extension to the directory, but it just causes an EISDIR exception.)
public void writeData(String dirName){
try
{
File root = new File(getExternalFilesDir(null), dirName);
// Writes to file
//
// The "true" argument allows the file to be appended. Without this argument (just root),
// the file will be overwritten (even though we later call append) rather than appended to.
FileWriter writer = new FileWriter(root, true);
writer.append("Append This Text\n");
writer.flush();
writer.close();
// Checks if we actually wrote to file by reading it back in (appears in Log)
//readData(dirName);
}
catch(Exception e)
{
Log.v("2222", "2222 ERROR: " + e.getMessage());
}
}
If you're interested, here's the function I wrote to read in the data:
public void readData(String dirName){
try
{
File root = new File(getExternalFilesDir(null), dirName);
// Checks to see if we are actually writing to file by reading in the file
BufferedReader reader = new BufferedReader(new FileReader(root));
try {
String s = reader.readLine();
while (s != null) {
Log.v("2222", "2222 READ: " + s);
s = reader.readLine();
}
}
catch(Exception e) {
Log.v("2222", "2222 ERROR: " + e.getMessage());
}
finally {
reader.close();
}
}
catch(Exception e) {
Log.v("2222", "2222 ERROR: " + e.getMessage());
}
}
Thanks!
even if I connect it to a computer and search
if I clear my log (similar to a list of print statements shown within Eclipse) and disconnect my phone from my computer, then reconnect it, the log reappears with everything I've ever written to my file (even if I later overwrote it).
What you are seeing on your computer is what is indexed by MediaStore, and possibly a subset of those, depending upon whether your computer caches information it gets from the device in terms of "directory" contents.
To help ensure that MediaStore indexes your file promptly:
Use a FileOutputStream (optionally wrapped in an OutputStreamWriter), not a FileWriter
Call flush(), getFD().sync(), and close() on the FileOutputStream, instead of calling flush() and close() on the FileWriter (sync() will ensure the bytes are written to disk before continuing)
Use MediaScannerConnection and scanFile() to tell MediaStore to index your file
You can then use whatever sort of "reload" or "refresh" or whatever option is in your desktop OS's file manager, and your file should show up.
This blog post has more on all of this.
public void create(){
folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),"video");
boolean success = true;
if (!folder.exists()) {
success=folder.mkdirs();
}
if (success) {
readfile();
} else {
System.out.println("failed");
}
}
The above code will be used to crete the directory in th emobile at desired path
private void readfile() {
// TODO Auto-generated method stub
AssetManager assetManager = getResources().getAssets();
String[] files = null;
try {
files = assetManager.list("clipart");
} catch (Exception e) {
Log.e("read clipart ERROR", e.toString());
e.printStackTrace();
}
for(String filename : files) {
System.out.println("File name => "+filename);
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("clipart/" + filename);
out = new FileOutputStream(folder + "/" + filename);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(Exception e) {
Log.e("copy clipart ERROR", e.toString());
e.printStackTrace();
}
}}private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}}
this is my code used to write file in internal memory from the assets folder in project. This code can read all type(extension) of file from asset folder to mobile.
Don't forget to add permission in manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and call the above function by
readfile();//this call the function to read and write the file
I hope this may help you.
Thank you.
I'm working on a method which will take a zipped file, unzip it, and return a new file/directory containing all the unzipped files. The goal is to then take that directory and extract an excel document from it and then convert it into a Workbook class I built (which is fully unit tested and works fine). The problem is that I'm getting the following exception:
java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:215)
at java.util.zip.ZipFile.<init>(ZipFile.java:145)
at java.util.zip.ZipFile.<init>(ZipFile.java:159)
at com.atd.core.datamigrator.BulkImageUpload.createWorkbook(BulkImageUpload.java:54)
at com.atd.core.datamigrator.BulkImageUpload.importImages(BulkImageUpload.java:38)
at com.atd.core.datamigrator.BulkImageUpload.main(BulkImageUpload.java:236)
Here is my code
private Workbook createWorkbook(File file) {
File unZipedFile = unZip(file);
File[] files = unZipedFile.listFiles();
Workbook wBook = null;
for (int i = 0; i < files.length; i++) {
if (files[i].getName().contains(".xls")) {
try {
File f = files[i];
ZipFile zip = new ZipFile(f);
wBook = new Workbook(zip);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
return wBook;
}
private File unZip(File input) {
File output = new File("unzippedFile");
OutputStream out = null;
try {
ZipFile zipFile = new ZipFile(input);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File entryDestination = new File(output, entry.getName());
entryDestination.getParentFile().mkdirs();
InputStream in = zipFile.getInputStream(entry);
ZipInputStream zis = new ZipInputStream(in);
out = new FileOutputStream(entryDestination);
out.write(zis.read());
out.flush();
out.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return output;
}
I know this is a problem with the unzip method because when I use File f = new File("some path") instead of using the unzipped file, it works fine.
Also, File I/O was never my strong point, so be nice :)
Okay, I now believe that this is the problem:
ZipInputStream zis = new ZipInputStream(in);
out = new FileOutputStream(entryDestination);
out.write(zis.read());
out.flush();
out.close();
You're creating a new file, and writing a single byte to it. That's not going to be a valid Excel file of any description. You're also failing to close streams using finally blocks, but that's a different matter. To copy the contents of one stream to another, you want something like:
byte[] buffer = new byte[8192];
int bytes;
while ((bytes = input.read(buffer)) > 0) {
output.write(buffer, 0, bytes);
}
That said, you'd be better off using a 3rd party library to hide all of this detail - look at Guava and its ByteStreams and Files classes for example.
It's worth taking a step back and working out why you didn't spot this problem for yourself, by the way. For example, the first thing I'd have done would be to look at the directory where the files were unzipped, and try to open those files. Just seeing a bunch of 1-byte files would be a bit of a giveaway. When trying to diagnose an issue, it's vital that you can split a big problem into small ones, and work out which small one is at fault.
I have developed a java program that copies the file from source folder to destination folder
there are 10 serialized files that it copies from source folder to destination folder
but one thing is missing in it is that let say if the files are already exists in the destination folder then in that case it should not copy
so basically a look is done within in one second that will check the destination folder contain those 10 serialized files or not
if not then in that case only it should copy and after copying it should again check within in second whether file exists or not , Please advise how to achieve this
//Create a class extends with TimerTask
class ScheduledTask extends TimerTask {
public void run() {
InputStream inStream = null;
OutputStream outStream = null;
try {
File source = new File("C:\\cache\\");
File target = new File("C:\\Authclient\\cache\\");
// Already exists. do not copy
/*if (target.exists()) {
return;
}*/
File[] files = source.listFiles();
for (File file : files) {
inStream = new FileInputStream(file);
outStream = new FileOutputStream(target + "/" + file.getName());
byte[] buffer = new byte[1024];
int length;
// copy the file content in bytes
while ((length = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
}
inStream.close();
outStream.close();
}
System.out.println("File is copied successful!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Copycache {
public static void main(String args[]) throws InterruptedException {
Timer time = new Timer();
ScheduledTask task = new ScheduledTask();
time.schedule(task, new Date(), TimeUnit.SECONDS.toMillis(1));
}
}
the above exists implementation which is commented is not working correct rite now please advise
I am curious about your exact requirements. Consider this small example:
File file = new File("test.txt");
if (!file.exists())
{
FileOutputStream fis = new FileOutputStream(file);
fis.write("blabla".getBytes());
fis.close();
}
Now put a breakpoint on the line FileOutputStream fis...
Run it and wait at the breakpoint, then create the test.txt manually and put some data in it.
Then continue running the program.
Your program will overwrite the contents of test.txt without warning.
If timing is so crucial here you will need to figure out a different solution.
Edit: I got curious and did some more testing. It seems it won't even throw an exception if you add the line file.createNewFile();, break there, create the file and then continue the application. I wonder why..