I have this DownloadFile.java and downloads the file as it should:
import java.io.*;
import java.net.URL;
public class DownloadFile {
public static void main(String[] args) throws IOException {
String fileName = "setup.exe";
// The file that will be saved on your computer
URL link = new URL("http://onlinebackup.elgiganten.se/software/elgiganten/setup.exe");
// The file that you want to download
// Code to download
InputStream in = new BufferedInputStream(link.openStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
byte[] response = out.toByteArray();
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(response);
fos.close();
// End download code
System.out.println("Finished");
}
}
I want to execute this from a mouse event in Gui.java.
private void jLabel17MouseClicked(java.awt.event.MouseEvent evt){
}
How do I do this?
Your current method is a static method, which is fine, but all the data that it extracts is held tightly within the main method, preventing other classes from using it, but fortunately this can be corrected.
My suggestion:
re-write your DownloadFile code so that it is does not simply a static main method, but rather a method that can be called by other classes easily, and that returns the data from the file of interest. This way outside classes can call the method and then receive the data that the method extracted.
Give it a String parameter that will allow the calling code to pass in the URL address.
Give it a File parameter for the file that it should write data to.
Consider having it return data (a byte array?), if this data will be needed by the calling program.
Or if it does not need to return data, perhaps it could return boolean to indicate if the download was successful or not.
Make sure that your method throws all exceptions (such as IO and URL excptions) that it needs to throw.
Also, if this is to be called by a Swing GUI, be sure to call this type of code in a background thread, such as in a SwingWorker, so that this code does not tie up the Swing event thread, rendering your GUI frozen for a time.
Related
I want to create a link that would initiate a file download which would be asynchronous to the page itself, i.e. I want the page not to be locked during the file download. Should I make it be initiated outside wicket? Or is there something inside wicket that would let me set up a resource stream which would bypass the page locks?
Things I tried:
DownloadLink - locks the page, as stated in its doc. This was my starting point.
ResourceLink - did not state the locking explicitly in the doc, so I tried this, but it also locked the page.
At this point I've investigated the code of both links a bit and noticed they both schedule the download via ResourceStreamRequestHandler. Expecting that his kind of behavior could be just handler-specific I've attempted to schedule a custom handler I've written:
private void sendFile(final File file) throws IOException {
IRequestHandler fileDownloadHandler = new IRequestHandler() {
#Override
public void respond(IRequestCycle requestCycle) {
WebResponse response = (WebResponse) requestCycle.getResponse();
OutputStream outStream = response.getOutputStream();
response.setContentType("audio/x-wav");
response.setContentLength((int)file.length());
String fileName = "Somethingsomething.wav";
// sets HTTP header
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
byte[] byteBuffer = new byte[1024];
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(file));
int length = 0;
// reads the file's bytes and writes them to the response stream
while ((in != null) && ((length = in.read(byteBuffer)) != -1))
{
outStream.write(byteBuffer,0,length);
}
in.close();
outStream.close();
} catch (IOException e) {
throw new PortalError("IOException trying to write the response", e);
}
}
#Override
public void detach(IRequestCycle requestCycle) {
}
};
getRequestCycle().scheduleRequestHandlerAfterCurrent(fileDownloadHandler);
}
This did not quite work either, so I've investigated further. I've noticed that unlike I expected, the "scheduled" request handlers would not get executed on a separate request, as I expected, but on the same one. I figured that it must be that the page gets locked for the first handler and then remains locked while the second one is executing as well. So I've attempted to force the download handler into a separate request (via an ajax behaviour):
public void startDownload(AjaxRequestTarget target) throws DownloadTargetNotFoundException{
target.appendJavaScript("setTimeout(\"window.location.href='" + getCallbackUrl() + "'\", 100);");
}
#Override
public void onRequest() {
sendFile(getFile());
logger.debug("Download initiated");
}
I've found this here and hoped it could potentially be what I've been looking for. However, unsurprisingly so, the page gets locked still (I would imagine because the behaviour still has to be retrieved from the page, for which the page lock has to be acquired).
I'm at a loss where I should be looking next, especially after all this time trying to get a simple download link working. I was considering creating another web filter one layer above wicket, which could be signaled from within wicket to create the download after the wicket filter is finished with its work (and hence the page lock is already released), but that seems a bit excessive for a task like this.
Any suggestions are welcome.
You have to download from a resource, see
http://wicketinaction.com/2012/11/uploading-files-to-wicket-iresource/ and read http://wicket.apache.org/guide/guide/resources.html
I'm having issues with reading decrypted data from conceal. It looks like I can't correctly finish streaming.
I pretend there is some issue with conceal, because of when I switch my proxyStream (just the encryption part) to not run it through conceal, everything works as expected. I'm also assuming that writing is ok, there is no exception whatsoever and I can find the encrypted file on disk.
I'm proxying my data through contentprovider to allow other apps read decrypted data when the user wants it. (sharing,...)
In my content provider I'm using the openFile method to allow contentResolvers read the data
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
String name = uri.getLastPathSegment();
File file = new File(name);
InputStream fileContents = mStorageProxy.getDecryptInputStream(file);
ParcelFileDescriptor.AutoCloseOutputStream stream = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
PipeThread pipeThread = new PipeThread(fileContents, stream);
pipeThread.start();
return pipe[0];
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
I guess in the Facebook app Facebook android team could be rather using a standard query() method with a byte array sent in MediaStore.MediaColumns() which is not suitable for me because of I'm not only encrypting media files and I also like the approach of streams better.
This is how I'm reading from the Inpustream. It's basically a pipe between two parcelFileDescriptors. The inputstream comes from conceal and it is a FileInputstream wrapped into a BufferedInputStream originaly.
static class PipeThread extends Thread {
InputStream input;
OutputStream out;
PipeThread(InputStream inputStream, OutputStream out) {
this.input=inputStream;
this.out=out;
}
#Override
public void run() {
byte[] buf=new byte[1024];
int len;
try {
while ((len=input.read(buf)) > 0) {
out.write(buf, 0, len);
}
input.close();
out.flush();
out.close();
}
catch (IOException e) {
Log.e(getClass().getSimpleName(),
"Exception transferring file", e);
}
}
}
I've tried other methods how to read the stream, so it really shouldn't be the issue.
Finally here's the exception I'm constantly ending up with. Do you know what could be the issue? It points to native calls, which I got lost in..
Exception transferring file
com.facebook.crypto.cipher.NativeGCMCipherException: decryptFinal
at com.facebook.crypto.cipher.NativeGCMCipher.decryptFinal(NativeGCMCipher.java:108)
at com.facebook.crypto.streams.NativeGCMCipherInputStream.ensureTagValid(NativeGCMCipherInputStream.java:126)
at com.facebook.crypto.streams.NativeGCMCipherInputStream.read(NativeGCMCipherInputStream.java:91)
at com.facebook.crypto.streams.NativeGCMCipherInputStream.read(NativeGCMCipherInputStream.java:76)
EDIT:
It looks like the stream is working ok, but what fails is the last iteration of reading from it. As I'm using buffer it seems like the fact that the buffer is bigger then the amount of remaiming data is causing the issue. I've been looking into sources of conceal and it seems to be ok from this regard there. Couldn't it be failing somewhere in the native layer?
Note: I've managed to get the decrypted file except its final chunk of bytes..So I have for example an incomplete image file (with last few thousands of pixels not being displayed)
From my little experience with conceal, I have noticed that, only the same application that encrypts a file could decrypt it successfully irrespective whether it has the same package or not. Be sure to put this in mind
This was resolved in https://github.com/facebook/conceal/issues/24. For posterity's sake, the problem here is that the author forgot to call close() on the output stream.
I load a file at a servlet, use .getClassLoader().getResourceAsStream(path), path is in WEB-INF/classes dir, I found after I changed path file content, but file servlet loads are the same, don't change, file is cached.
example code:
This method always gets the same result every time, after I change the test.key content
private String getKey(String param){
String name = "keys/"+param+"/test.key";
InputStream in = XXXServlet.class.getClassLoader().getResourceAsStream(name);
StringBuilder builder = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while((line = reader.readLine()) != null){
builder.append(line).append("\n");
}
} catch (IOException ignoreException) {
}finally{
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
String result = builder.toString();
return result;
}
=================================================================
change these two lines code, it works fine
String name = "/WEB-INF/classes/keys/"+param+"/test.key";
InputStream in = getServletContext().getResourceAsStream(name);
Ankur is right. An existing class loader trying to get a class or resource (regardless of the name and path to the file/inputstream) will never reload if the name and associated content has already been loaded once by the class loader or it's parent. This is for performance reasons. The only way to do it is to create a new instance of a class loader and do it again. But then, at least with classes, you'll have to worry about incompatible classes running together in the system. Like you can't assign an instance of the new class to a variable that was typed with the class loaded by the first class loader instance since they're technically different classes.
Pabrantes thinks it is different because Liu is not loading a 'class' per say, but a key: "keys/"+param+"/test.key"; However he's using the classloader to do so and the rules are the same on loading 'name' with respect to getResourceAsStream(name). Doesn't matter if it's a class or not, classloader will think "Oh here you go, I've already loaded the byte stream for 'name'". Pulls it right out of permgen. For those interested - if you create/implement your own version of a new classloader that reloads every time - just make sure it only does this for very specific paths or name patterns. Also keep in mind that every copy you load will likely get space in permgen so over time permgen will grow out of control unless you unload.
So - that's why it doesn't work. ContextLoader is good to use. :-)
Dan C.
This is because once you have loaded a class, you will get the same class contents even if you try to reload it. This is because it checks if the class contents are already loaded, if yes then it does not bother to load it once again just refers to the one already loaded(in memory).
To achieve reloading you need write a custom class loader, which will read the contents of the class (in bytes) and use these bytes to load the class.
Sample CustomClassLoader code :
public class CustomClassLoader extends ClassLoader {
private static final String CLASS_FOLDER_PATH = "/lib/all-classfiles/";
private static final String CLASS_FILE_EXTENSION = ".class";
/**
* Loads the class file in memory
*/
#Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
return findClass(className);
}
#Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
try {
byte[] bytes = loadClassData(className);
// Build the class based on the byte data
return defineClass(className, bytes, 0, bytes.length);
} catch (IOException ioException) {
// Call super class(ClassLoader) implementation of loadClass() method
return super.loadClass(className);
}
}
/**
* Returns the byte contents of the class file
*
* #param className
* #return byte[] - class file data
* #throws IOException
*/
private byte[] loadClassData(String className) throws IOException {
File classFile = new File(CLASS_FOLDER_PATH + className + CLASS_FILE_EXTENSION);
int fileSize = (int) classFile.length();
// Read the file bytes in byte array
byte buff[] = new byte[fileSize];
FileInputStream fis = null;
DataInputStream dis = null;
fis = new FileInputStream(classFile);
dis = new DataInputStream(fis);
// Read the byte contents of the ORM class file for loading the class
dis.readFully(buff);
dis.close();
fis.close();
return buff;
}
}
Make sure that your class loader instance is garbage collected when you want to reload the contents of the class. Or else you may end up reading cached class data.
There are many more things you need to take care of while reloading. Please read this article on Class Reloading to understand it in detail.
Hope this helps.
I do not have experience using Java channels. I would like to write a byte array to a file. Currently, I have the following code:
String outFileString = DEFAULT_DECODED_FILE; // Valid file pathname
FileSystem fs = FileSystems.getDefault();
Path fp = fs.getPath(outFileString);
FileChannel outChannel = FileChannel.open(fp, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE));
// Please note: result.getRawBytes() returns a byte[]
ByteBuffer buffer = ByteBuffer.allocate(result.getRawBytes().length);
buffer.put(result.getRawBytes());
outChannel.write(buffer); // File successfully created/truncated, but no data
With this code, the output file is created, and truncated if it exists. Also, in the IntelliJ debugger, I can see that buffer contains data. Also, the line outChannel.write() is successfully called without throwing an exception. However, after the program exits, the data does not appear in the output file.
Can somebody (a) tell me if the FileChannel API is an acceptable choice for writing a byte array to a file, and (b) if so, how should the above code be modified to get it to work?
As gulyan points out, you need to flip() your byte buffer before writing it. Alternately, you could wrap your original byte array:
ByteBuffer buffer = ByteBuffer.wrap(result.getRawBytes());
To guarantee the write is on disk, you need to use force():
outChannel.force(false);
Or you could close the channel:
outChannel.close();
You should call:
buffer.flip();
before the write.
This prepares the buffer for reading.
Also, you should call
buffer.clear();
before putting data into it.
To answer your first question
tell me if the FileChannel API is an acceptable choice for writing a byte array to a file
It's ok but there's simpler ways. Try using a FileOutputStream. Typically this would be wrapped by a BufferedOutputStream for performance but the key is both of these extend OutputStream which has a simple write(byte[]) method. This is much easier to work with than the channel/buffer API.
Here is a complete example of FileChannel.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
public class FileChannelTest {
// This is a Filer location where write operation to be done.
private static final String FILER_LOCATION = "C:\\documents\\test";
// This is a text message that to be written in filer location file.
private static final String MESSAGE_WRITE_ON_FILER = "Operation has been committed.";
public static void main(String[] args) throws FileNotFoundException {
// Initialized the File and File Channel
RandomAccessFile randomAccessFileOutputFile = null;
FileChannel outputFileChannel = null;
try {
// Create a random access file with 'rw' permission..
randomAccessFileOutputFile = new RandomAccessFile(FILER_LOCATION + File.separator + "readme.txt", "rw");
outputFileChannel = randomAccessFileOutputFile.getChannel();
//Read line of code one by one and converted it into byte array to write into FileChannel.
final byte[] bytes = (MESSAGE_WRITE_ON_FILER + System.lineSeparator()).getBytes();
// Defined a new buffer capacity.
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
// Put byte array into butter array.
buffer.put(bytes);
// its flip the buffer and set the position to zero for next write operation.
buffer.flip();
/**
* Writes a sequence of bytes to this channel from the given buffer.
*/
outputFileChannel.write(buffer);
System.out.println("File Write Operation is done!!");
} catch (IOException ex) {
System.out.println("Oops Unable to proceed file write Operation due to ->" + ex.getMessage());
} finally {
try {
outputFileChannel.close();
randomAccessFileOutputFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Is it possible to ObjectOutputStream/ObjectInputStream an internal class? I can write it OK, and examine the created file, but when I try to read it back in using ObjectInputStream, I get an EOFException just trying to read an Object o = oos.readObject();
I use the same File object to open both streams, so that's not the problem.
It seems to be independant of the nature of the internal Class - a class with just a public int fails identically to a more complex class.
I have to move on, and create a regular class, and instantiate in the sender class, but I hate to walk away not knowing if it is possible, and if not why not.
Update: Related issues that were the cause of the problem:
A. You cannot re-open a file written with an ObjectOutputStream and append: a second header is written and corrupts the file.
B. Serializing a HashMap using ByteOutputStream to do a hash digest doesn't work, because when you read the HashMap back in from a ObjectOutputStream file, you may very well get a different byte[] from ByteOutputStream because of variations in pair order: the content is the same, but the byte[] (and so the hash disgest) is not.
Hope this helps someone save some time.
This one works for me. Please look for any differences to your solution.
public class Example implements Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
new Example().run();
}
private void run() throws IOException, ClassNotFoundException {
Inner inner = new Inner();
inner.x = 5;
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream( out );
outputStream.writeObject( inner );
ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
ObjectInputStream inputStream = new ObjectInputStream( in );
Inner inner2 = (Inner) inputStream.readObject();
System.out.println( inner2.x );
}
class Inner implements Serializable {
int x;
}
}
Can you include a small bit of sample code? The most obvious explanation is that you're not closing / flushing the output stream before you try to read it back in.