Download and save a file using Java - java

Let's say I have an URL, like something.domain/myfile.txt then I want to save this file, with that "Save File" dialog.
I tried my best to do it, but everytime I save the file using the dialog the file is not there.
An example or somewhere I can find information on this would help a lot!
URL website = null;
try {
website = new URL(<insert url here>);
} catch (MalformedURLException e) {
e.printStackTrace();
}
ReadableByteChannel rbc = null;
try {
rbc = Channels.newChannel(website.openStream());
} catch (IOException e2) {
e2.printStackTrace();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("minecraft.jar"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
fos.getChannel().transferFrom(rbc, 0, 1 << 24);
} catch (IOException e) {
e.printStackTrace();
}
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(fileChooser) == JFileChooser.APPROVE_OPTION) {
File dir = fileChooser.getCurrentDirectory();
dir.mkdir();
//After this point is where I need help.

I trust that this is what you're looking for:
if (fileChooser.showSaveDialog(fileChooser) == JFileChooser.APPROVE_OPTION)
{
File file = fileChooser.getSelectedFile();
// whatever you want to do with the file
System.out.println("The file is "+file.getAbsolutePath());
// fos = new FileOutputStream(file) ...
}

Did you notice that in your code you are trying to save/download the file before giving the user the option to chose the destination?
I would split the code into three different operations:
A method in charge of transferring the bytes from the InputStream (the web) to the OutputStream (the file).
a method to show the user a dialog so he can chose where to store the file.
the method that completes the whole task: choose a file and transfer the bytes from the web to it.
1) Would be something like this (you don't need to use the NIO API to implement it):
public void transfer(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
}
2) would be something very similar to what Dukeling has already stated:
public File chooseFile() {
File result = null;
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(fileChooser) == JFileChooser.APPROVE_OPTION) {
result = fileChooser.getSelectedFile();
}
return result;
}
3) then, combining these two operations together is really simple:
public void saveFileFromWeb(URL url) {
File file = chooseFile(); // 1. Choose the destination file
if (file != null) {
// 2. Create parent folder structure
File folder = file.getParentFile();
if (!folder.exist()) {
folder.mkdirs();
}
InputStream in = null;
OutputStream out = null;
try {
// 3. Initialise streams
in = url.openStream();
out = new FileOuputStream(file);
// 4. Transfer data
transfer(in, out);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. close streams
if (in != null) {
try {
in.close();
} catch (IOException e) { /* ignore */ }
}
if (out != null) {
try {
out.close();
} catch (IOException e) { /* ignore */ }
}
}
}
NOTE: 1) and 2) could be private methods. Of course you could do this is just one single operation but splitting it would give you an overview of the different steps to perform.
NOTE 2: I simplified the exception handling part

Related

Check the Succesfull Copy of a File

I am trying to make a file manager app in Android.
I want to provide the user with an option to move their files. So first I am copying the Files then I am deleting the file if there is no error.
This is the code I am using to copy the files
public static boolean copy(File copy, String directory, Context con) {
static FileInputStream inStream = null;
static OutputStream outStream = null;
DocumentFile dir = getDocumentFileIfAllowedToWrite(new File(directory), con);
String mime = "";
DocumentFile copy1 = dir.createFile(mime, copy.getName());
try {
inStream = new FileInputStream(copy);
outStream = con.getContentResolver().openOutputStream(copy1.getUri());
byte[] buffer = new byte[16384];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inStream.close();
outStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
But in one of my devices the files are simply getting deleted without copying.
So my thought is that I will check the length of the file by SourceFile.length() and the length of the DestinationFile.length() if both are same or not. If both are same then I will delete the SourceFile.
Is the most effective way to check it without checking the MD5 of an File? Also what are the chances that the file transfer is incomplete/corrupted and still the length is same?

My deflater class works incorecctly

My compression class works incorrectly. When i am trying to compress simple file that contains sentence "something", compressed and uncompressed returns something other. Here is my deflating code:
public static void inflate(String arg) throws Exception {
try {
FileInputStream fin = new FileInputStream(arg);
InflaterInputStream in = new InflaterInputStream(fin);
FileOutputStream fout = new FileOutputStream("def.txt");
int i;
while ((i = in.read()) != -1) {
fout.write((byte) i);
fout.flush();
}
fin.close();
fout.close();
in.close();
} catch (Exception e) {
System.out.println(e);
}
new File(arg).delete();
new File("def.txt").renameTo(new File(arg));
}
public static void deflate(String arg) throws Exception {
try {
FileInputStream fin = new FileInputStream(arg);
FileOutputStream fout = new FileOutputStream("def.txt");
DeflaterOutputStream out = new DeflaterOutputStream(fout);
int i;
while ((i = fin.read()) != -1) {
out.write((byte) i);
out.flush();
}
fin.close();
out.close();
} catch (Exception e) {
System.out.println(e);
}
new File(arg).delete();
new File("def.txt").renameTo(new File(arg));
}
I call it using
public static void main(String[] args) {
try {
Main.deflate(args[0]);
Main.inflate(args[0]);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So how to fix my code? I think that problem is not in deflating code.
Your code does seem to work as expected.
Running it on a text file containing the word 'something' returns an identical file.
To confirm that the output is the same, try editing the following lines:
Test.inflate("def.txt");
which is in your main function and
FileOutputStream fout = new FileOutputStream("output.txt");
from your inflate function.
Then comment out the following lines in both your deflate() and inflate() functions
//new File(arg).delete();
//new File("def.txt").renameTo(new File(arg));
The program will now take an input file, I used input.txt with the word 'something' as per your example, and create a deflated file def.txt and an output.txt file that is created by inflating def.txt.
The output file should match the input file exactly, while the deflated file should be different. If not, there must be some further information about the program that is missing.

apache.commons.net.ftp.FTPClient not uploading the file to the required folder

I'm using the following code to upload an xml file to the directory /home/domainname/public_html/guest in the server. However, the file is uploaded only to the location /home/domainname. It is not uploading to the child directories. Please advise.
FTPClient client = new FTPClient();
FileInputStream fis = null;
try {
client.connect(Util.getProductsXMLFTPServer());
client.login(Util.getProductsXMLFTPUser(), Util.getProductsXMLFTPPassword());
//
// Create an InputStream of the file to be uploaded
//
fis = new FileInputStream(new File(Util.getProductsXMLFTPInputFilePath(), Util.getProductsXMLFTPOutputFileName()));
client.changeWorkingDirectory(Util.getProductsXMLFTPUploadPath());
client.storeFile(Util.getProductsXMLFTPOutputFileName(), fis);
client.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
I checked your code, it works. I've only changed file type declaration to binary, which may be not needed for XML files.
Here's my complete code for reference:
package apachenet.ftp;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
public class App {
public static void main( String[] args ) {
FTPClient client = new FTPClient();
FileInputStream fis = null;
try {
client.connect(/*Util.getProductsXMLFTPServer()*/"127.0.0.1");
client.login(/*Util.getProductsXMLFTPUser()*/"pwyrwinski",
/*Util.getProductsXMLFTPPassword()*/"secret");
client.setFileType(FTP.BINARY_FILE_TYPE); // optional
fis = new FileInputStream(
new File(/* Util.getProductsXMLFTPInputFilePath() */"/home/pwyrwinski",
/* Util.getProductsXMLFTPOutputFileName() */"img.png"));
client.changeWorkingDirectory(/*Util.getProductsXMLFTPUploadPath()*/ "someDir");
client.storeFile(/*Util.getProductsXMLFTPOutputFileName()*/"img_bis.png", fis);
client.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
As you can see it's roughly the same as yours.
Util class calls are replaced with raw data.
When I ran it, file /home/pwyrwinski/img.png was uploaded to {FTP_USER_ROOT}/someDir directory on ftp server with name changed to img_bis.png. I assume this is exactly what you wanted to achieve.
Let's go back to your problem.
Try to check what is returned from
Util.getProductsXMLFTPUploadPath() call. My guess is it's not what
you're expecting - so debug it in your IDE or print it to the console.
Check if path returned from Util.getProductsXMLFTPUploadPath()
call starts with slash, it shouldn't.
UPDATE 1.
Does direcory /home/domainname/public_html/guest exist on server?
Add following method to your class:
private static void showServerReply(FTPClient ftpClient) {
String[] replies = ftpClient.getReplyStrings();
if (replies != null && replies.length > 0) {
for (String aReply : replies) {
System.out.println("SERVER: " + aReply);
}
}
}
and call it after every ftp-client's method call. This will give you codes and descriptions of every command result. I suspect client.changeWorkingDirectory(...) ends with error, probably: 550 Permission Denied (or No such file or folder).
Next modification will be:
client.login(Util.getProductsXMLFTPUser(), Util.getProductsXMLFTPPassword());
System.out.println(client.printWorkingDirectory()); // added this line!
this will tell us what is current working directory after login in.
Please post your results.
FTPClient ftpClient = new FTPClient();
try {
System.out.println("before server connection");
ftpClient.connect(server, port);
System.out.println("before user name and passwod");
ftpClient.login(user, pass);
ftpClient.enterLocalActiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
System.out.println("connection sucess");
// windows working fine
File secondLocalFile = new File("/home/aims/archived_reports/tes_S_000000123/test.pdf");
// String secondRemoteFile = "/archived_reports/PermanentRecord.pdf";
//linux
// File secondLocalFile = new File("/archived_reports/tes_S_000009123/test.pdf");
String secondRemoteFile = "remotefilename.pdf";
InputStream inputStream = new FileInputStream(secondLocalFile);
System.out.println("Start uploading second file");
ftpClient.changeWorkingDirectory("/reports");// home/ftp.test/reports folder
System.out.println("Prasent Working Directory :"+ftpClient.printWorkingDirectory());
OutputStream outputStream = ftpClient.storeFileStream(secondRemoteFile);
int returnCode = ftpClient.getReplyCode();
System.out.println(returnCode);
byte[] bytesIn = new byte[4096];
int read = 1;
while ((read = inputStream.read(bytesIn)) != -1) {
outputStream.write(bytesIn, 0, read);
}
System.out.println();
inputStream.close();
outputStream.close();
boolean completed = ftpClient.completePendingCommand();
if (completed) {
System.out.println("The second file is uploaded successfully.");
}

Unnecessary file structure is added while "zipping" a directory using java?

well my question is really simple, is about an unexpected behavior (or at least is unexpected to me) while I try to zip a directory, I have the following methods that I've created on my own (I'm quite aware that I'm not handling exceptions and all that stuff, It is because (by now) I'm just doing this to learn how to do it so stability "is not really important"), here is the code:
public static void zipDirectory(File srcDirectory, File zipFile) throws IllegalArgumentException {
if (!srcDirectory.isDirectory()) {
throw new IllegalArgumentException("The first parameter (srcDirectory) MUST be a directory.");
}
int bytesRead;
byte[] dataRead = new byte[1000];
BufferedInputStream in = null;
ZipOutputStream zOut;
try {
zOut = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
for (File f : srcDirectory.listFiles()) {
if (f.isDirectory()) {
FileUtilities.zipInnerDirectory(f,zOut);
}else {
in = new BufferedInputStream(new FileInputStream(f.getAbsolutePath()), 1000);
zOut.putNextEntry(new ZipEntry(f.getPath()));
while((bytesRead = in.read(dataRead,0,1000)) != -1) {
zOut.write(dataRead, 0, bytesRead);
}
zOut.closeEntry();
}
}
zOut.flush();
zOut.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void zipInnerDirectory(File dir, ZipOutputStream zOut) throws IllegalArgumentException {
if (!dir.isDirectory()) {
throw new IllegalArgumentException("The first parameter (srcDirectory) MUST be a directory.");
}
BufferedInputStream in = null;
int bytesRead;
byte[] dataRead = new byte[1000];
try {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
FileUtilities.zipInnerDirectory(f,zOut);
}else {
in = new BufferedInputStream(new FileInputStream(f.getAbsolutePath()), 1000);
zOut.putNextEntry(new ZipEntry(f.getPath()));
while((bytesRead = in.read(dataRead,0,1000)) != -1) {
zOut.write(dataRead, 0, bytesRead);
}
zOut.closeEntry();
}
}
zOut.flush();
zOut.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
As I said is not my best coding so please don't judge the code (or at least don't be too strict ;) ), I know it can be so much better; ok the "unexpected behavior" is this, let's say that I have the following directory:
H:\MyDir1\MyDir2\MyDirToZip
when i send as a parameter a file created with that path (new File("H:\\MyDir1\\MyDir2\\MyDirToZip")) everything's work pretty fine the zip is created successfully, the thing is that when I open (unzip) the files inside the zip they have the next structure:
H:\MyDir1\MyDir2\MyDirToZip
when I was expecting to find inside just:
\MyDirToZip
without H: \MyDir1 \MyDir2 which are "unnecessary" (BTW they just contain one to each other in the appropriate order, i mean, the other files that are in them are not compressed, that is why I say they are unnecessary) so the question is, what I'm I doing wrong? how can I specify that I just want to zip the structure down the srcDirectory?
zOut.putNextEntry(new ZipEntry(f.getPath()));
This should be the problem. f.getPath() will return a path that's relative to some root directory (probably your current working dir), but not relative to the directory you are zipping. You need to figure out a way to get the relative path from the zip directory, possibly this will do:
new ZipEntry(f.getAbsolutePath().substring(zipDir.getAbsolutePath().length()))
or, if you want the root directory added:
new ZipEntry(zipDir.getName() + "/"
+ f.getAbsolutePath().substring(zipDir.getAbsolutePath().length()))

How to check if a generated zip file is corrupted?

we have a piece of code which generates a zip file on our system. Everything is ok, but sometimes this zip file while opened by FilZip or WinZip is considered to be corrupted.
So here is my question: how can we check programatically if a generated zip file is corrupted?
Here is the code we are using to generate our zip files:
try {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpFile));
byte[] buffer = new byte[16384];
int contador = -1;
for (DigitalFile digitalFile : document.getDigitalFiles().getContent()) {
ZipEntry entry = new ZipEntry(digitalFile.getName());
FileInputStream fis = new FileInputStream(digitalFile.getFile());
try {
zos.putNextEntry(entry);
while ((counter = fis.read(buffer)) != -1) {
zos.write(buffer, 0, counter);
}
fis.close();
zos.closeEntry();
} catch (IOException ex) {
throw new OurException("It was not possible to read this file " + arquivo.getId());
}
}
try {
zos.close();
} catch (IOException ex) {
throw new OurException("We couldn't close this stream", ex);
}
Is there anything we are doing wrong here?
EDIT:
Actually, the code above is absolutely ok. My problem was that I was redirecting the WRONG stream for my users. So, instead of opening a zip file they where opening something completely different. Mea culpa :(
BUT the main question remains: how programatically I can verify if a given zip file is not corrupted?
You can use the ZipFile class to check your file :
static boolean isValid(final File file) {
ZipFile zipfile = null;
try {
zipfile = new ZipFile(file);
return true;
} catch (IOException e) {
return false;
} finally {
try {
if (zipfile != null) {
zipfile.close();
zipfile = null;
}
} catch (IOException e) {
}
}
}
I know its been a while that this has been posted, I have used the code that all of you provided and came up with this. This is working great for the actual question. Checking if the zip file is corrupted or not
private boolean isValid(File file) {
ZipFile zipfile = null;
ZipInputStream zis = null;
try {
zipfile = new ZipFile(file);
zis = new ZipInputStream(new FileInputStream(file));
ZipEntry ze = zis.getNextEntry();
if(ze == null) {
return false;
}
while(ze != null) {
// if it throws an exception fetching any of the following then we know the file is corrupted.
zipfile.getInputStream(ze);
ze.getCrc();
ze.getCompressedSize();
ze.getName();
ze = zis.getNextEntry();
}
return true;
} catch (ZipException e) {
return false;
} catch (IOException e) {
return false;
} finally {
try {
if (zipfile != null) {
zipfile.close();
zipfile = null;
}
} catch (IOException e) {
return false;
} try {
if (zis != null) {
zis.close();
zis = null;
}
} catch (IOException e) {
return false;
}
}
}
I think you'll see correspondent exception stack trace during zip-file generation. So, you probably wan't to enhance your exception handling.
in my implementation it looks like that. maybe it helps you:
//[...]
try {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
zos.putNextEntry(new ZipEntry(file.getName()));
try {
final byte[] buf = new byte[BUFFER_SIZE];
while (true) {
final int len = bis.read(buf);
if (len == -1) {
break;
}
zos.write(buf, 0, len);
}
zos.flush();
zos.closeEntry();
} finally {
try {
bis.close();
} catch (IOException e) {
LOG.debug("Buffered Stream closing failed");
} finally {
fis.close();
}
}
} catch (IOException e) {
throw new Exception(e);
}
//[...]
zos.close
Perhaps swap the following two lines?;
fis.close();
zos.closeEntry();
I can imagine that the closeEntry() will still read some data from the stream.
Your code is basically OK, try to find out which file is responsible for the corrupted zip file. Check whether digitalFile.getFile() always returns a valid and accessible argument to FileInputStream. Just add a bit logging to your code and you will find out what's wrong.
new ZipFile(file)
compress again the file, so duplicate efforts and that is not what you are looking for. Despite of the fact that only check one file and the question compress n-files.
Take a look to this: http://www.kodejava.org/examples/336.html
Create a checksum for your zip:
CheckedOutputStream checksum = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum));
...
And when you finish the compression show it
System.out.println("Checksum : " + checksum.getChecksum().getValue());
You must do the same reading the zip with java or others tools checking if checksums match.
see https://stackoverflow.com/a/10689488/848072 for more information
ZipOutputStream does not close the underlying stream.
What you need to do is:
FileOutputStream fos = new FileOutputStream(...);
ZipOutputStream zos = new ZipOutputStream(fos);
Then in your closing block:
zos.close();
fos.flush(); // Can't remember whether this is necessary off the top of my head!
fos.close();

Categories