How can I download .class file and and load it into jvm using class loader , I have write a simple code simulates downloading a .class file the I tried to load it into JVM
public class face {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
File f = new File("Task.class");
int count;
byte[] buffer = new byte[1024];
DataInputStream dis = new DataInputStream(new FileInputStream(f));
StringBuilder all = new StringBuilder();
while ((count = dis.read(buffer)) > 0) {
// System.out.write(buffer, 0, count);
all.append(buffer);
// System.out.flush();
}
File b = new File("Task.class");
FileOutputStream fos = new FileOutputStream(b);
DataOutputStream dos = new DataOutputStream(fos);
dos.write(all.toString().getBytes());
ClassLoader lod = face.class.getClassLoader();
lod.loadClass(b.getAbsolutePath());
}
}
Use Class.forName(<package_qualified_class_name>)
First, I would like to applogies for the long list of suggestion here, but you have managed to cram an impressive number of mistakes into a small piece of code.
I suggest don't do any of these things
don't use DataInputStream or DataOutputStream when it doesn't add anything. You don't use any method which requires it.
don't write binary data to a StringBuilder. A StringBuilder is for text.
don't copy an entire buffer if you only read part of it. i.e. you need to record the length actual read and copy only the amount used.
don't append a byte[] to a StringBuilder. It won't do what you expect.
don't use a String to store binary data.
don't convert a String to byte[] using the default encoding unless you know you have ASCII data (which you don't)
don't write to a file you just read. As this doesn't make sense. You should have tested this works without the file copy and you would have found this didn't work, before you attempted something more complicated.
you can't write to a file which you still have open in windows. I suggest you close() a file when you are finished with it.
don't attempt to load a class using the file name. You load it by package.class name.
I suggest you try a one liner to load a class first and show this works. The class should appear in your class path, and when you write to the file, you should write it to a directory appropriate for the package.
Instead of doing all this, you could add a http://yourserver/basepath to your class path and it will load the classes from a web service. i.e. you might be able to do this without writing any code at all.
Related
I have a problem generating ZIP files via zip4j.
I am able to produce ZIP archive using following code (I omitted some parts, that are not related to the issue), which is basically taken from zip4j tutorial:
File zipFile = new File(zipName);
ZipParameters params = new ZipParameters();
params.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
params.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
byte[] buffer = new byte[8192];
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
for (/* loop through list of input data */) {
String outputName = /* method to determine file name */;
try (InputStream in = /* method to get IS */ ) {
params.setFileNameInZip(outputName);
File tmpEntry = new File(outputName);
tmpEntry.createNewFile();
out.putNextEntry(tmpEntry, params);
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
tmpEntry.delete();
out.closeEntry();
in.close();
}
}
}
The problem is that although all files are correctly included in ZIP archive, their declared file size is 0. I can unzip them using "dumb" ZIP readers (like build-in TotalCommander's one), because all data are actually here, but more "clever" programs (like 7zip) produce CRC error and refuse to open them as corrupted.
I would say I need to declare the file size somehow (and I am definitely not doing this in my code snippet), but I was unable to find the (probably obvious) solution. I have googled that native java.util.zip.ZipEntry has .setSize() method, but I don't see anything like this in zip4j...
Anyone knows the correct approach to this?
So the solution is quite simple. One just needs to add following setting into ZipParameters:
params.setSourceExternalStream(true);
How I found that?
I digged deeper into the code and find following in closeEntry() method of CipherOutputStream.java class of zip4j:
if (zipParameters.isSourceExternalStream()) {
fileHeader.setUncompressedSize(totalBytesRead);
if (localFileHeader.getUncompressedSize() != totalBytesRead) {
localFileHeader.setUncompressedSize(totalBytesRead);
}
}
This is the only place where setUncompressedSize() - which sounds like having something to do with declared file size - method is called. So I got suspicious and tried to set the parameter in my code. And it does the job.
The lesson learned is that this example of using zip4j is incorrect because it is missing that vital line of code.
This question already has an answer here:
Get filename from an inputstream (Java)
(1 answer)
Closed 8 years ago.
I have a method accepts an InputStream as an argument. How do I find which file is being handled by the passed handler?
For example:
public performSomething(InputStream inputStream) {
System.out.println(FILENAME);
}
What should the FILENAME be replaced with such that the name of the file opened by the handler is displayed.
I guess you cannot, because the input stream might not belong to a file. It can be SocketInputStream, or ByteArrayInputStream for example. The input stream is just an abstraction
An input stream can be created to read from a file or from any other source of data. Therefore it makes no sense to have a filename attached to an input stream.
Simple Example :
InputStream input= assetInfo.openStream();
File t = new File("");
OutputStream out = new FileOutputStream(t);
int read=0;
byte[] bytes = new byte[1024];
while((read = input.read(bytes))!= -1){
out.write(bytes, 0, read);
}
Look in assetInfo to see if that class exposes that data (you can even look inside the class using reflection). Note that the creator or assetInfo made a design mistake not exposing this information, OR you are trying to make one now.
Even if you are certain you have a FileInputStream, you will still be unable to get the underlying file. FileInputStream does not retain its File argument, but immediately opens the file and retains just the FileDescriptor, a wrapper around the native int handle to the OS resource.
As of OpenJDK version 7, Update 40, a String path variable has been introduced, so with some luck you may try to reflectively get it.
Of course, this can be nothing more than heurstics. There is no official way through the public API.
I have a situation where I need to scan the runtime classpath for a resource file (say, res/config/meta.cfg), and then create a File handle for it. The best I've been able to come up with is:
// This file is located inside a JAR that is on the runtime classpath.
String fileName = "res/config/meta.cfg";
try {
InputStream inStream = ClassLoader.getSystemResourceAsStream(fileName);
File file = new File(String.format("${java.io.tmpdir}/%s", fileName));
FileOutputStream foutStream = null;
foutStream = new FileOutputStream(file);
int read = 0;
byte[] bytes = new byte[1024];
while((read = inStream.read(bytes)) != -1)
foutStream.write(bytes, 0, read);
foutStream.close();
return file;
} catch (Exception exc) {
throw new RuntimeException(exc);
}
So essentially, read in the resource as an InputStream, and then write the stream to a temp file (under {$java.io.tmpdir}) so that we can obtain a valid File handle for it.
This seems like going 3 sides around the barn. Is there a better/easier/more elegant way of doing this? Thanks in advance!
No.
Of course you can (and probably should) use a library to copy the InputStream's content to a file but that obviously is not the point of your question.
The classpath does not consist of directories only; resources can be inside archives (typically JARs) or on servers, and may not exist as something that can be accessed via a java.io.File object.
Typically the core problem is to use java.io.File objects where an InputStream would be sufficient. Sometimes you can't do anything against it when using a third-party library but it is a hint that the library designers didn't work very carefully. If you need the file handle in your own code you should have another look why it can't be an InputStream. Most of the time it can.
I am storing all of the bytes of an external .exe file, and then re-writing them to another .exe file that I am currently creating with FileOutputStream/BufferedOutputStream.
The bytes are written fine, and the second program is created in the location of my choice, but when I come to run the file, it says it's not a valid .exe file or not a valid 32/64bit application.
I'm guessing because it's not packed and generated properly.
How would I make it so it's an executable file and works the same as the first one?
p.s I can't use any copying of the file, because eventually I'm going to be encrypting the bytes and writing them to the file, but I still want it to be usable.
If all the bytes are identical it will run. If the original file runs and the copy doesn't then some of the bytes have to be different. It has nothing to do with packing.
Maybe you are using a byte variable to store the read data. Don't do that. Just use int. If you don't use byte variables correctly you can run into problems due to automatic sign extension.
This works fine for me
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
BufferedInputStream in = new BufferedInputStream(new FileInputStream("a.exe"));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("b.exe"));
int data = in.read();
while(data >= 0) {
out.write(data);
data = in.read();
}
in.close();
out.close();
}
}
I was handed some data in a file with an .dat extension. I need to read this data in a java program and build the data into some objects we defined. I tried the following, but it did not work
FileInputStream fstream = new FileInputStream("news.dat");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
Could someone tell me how to do this in java?
What kind of file is it? Is it a binary file which contains serialized Java objects? If so, then you rather need ObjectInputStream instead of DataInputStream to read it.
FileInputStream fis = new FileInputStream("news.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
// ...
(don't forget to properly handle resources using close() in finally, but that's beyond the scope of this question)
See also:
Basic serialization tutorial
A .dat file is usually a binary file, without any specific associated format. You can read the raw bytes of the file in a manner similar to what you posted - but you will need to interpret these bytes according to the underlying format. In particular, when you say "open" the file, what exactly do you want to happen in Java? What kind of objects do you want to be created? How should the stream of bytes map to these objects?
Once you know this, you can either write this layer yourself or use an existing API (assuming it's a standard format).
For reference, your example doesn't work because it assumes that the binary format is a character representation in the platform's default charset (as per the InputStreamReader constructor). And as you say it's binary, this will fail to convert the binary to a stream of characters (since, after all, it's not).
// BufferedInputStream not strictly needed, but much more efficient than reading
// one byte at a time
BufferedInputStream in = new BufferedInputStream (new FileInputStream("news.dat"));
This will give you a buffered stream which will return the raw bytes of the file; you can now either read and process them yourself, or pass this input stream to some library API that will create appropriate objects for you (if such a library exists).
That entirely depends on what sort of file the .dat is. Unfortunately, .dat is often used as a generic extension for a data file. It could be binary, in which case you could use FileInputStream fstream = new FileInputStream(new File("news.dat")); and call read() to get bytes from the file, or text, in which case you could use BufferedReader buff = new BufferedInputReader(new FileInputStream(new File("news.dat"))); and call readLine() to get each line of text. [edit]Or it could be Java objects in which case what BalusC said.[/edit]
In both cases, you'd then need to know what format the file was in to divide things up and get meaning from it, although this would be much easier if it was text as it could be done by inspection.
Please try the below code:
FileReader file = new FileReader(new File("File.dat"));
BufferedReader br = new BufferedReader(file);
String temp = br.readLine();
while (temp != null) {
temp = br.readLine();
System.out.println(temp);
}
A better way would be to use try-with-resources so that you would not have to worry about closing the resources.
Here is the code.
FileInputStream fis = new FileInputStream("news.dat");
try(ObjectInputStream objectstream = new ObjectInputStream(fis)){
objectstream.readObject();
}
catch(IOException e){
//
}