Extracting a jar from the currently running jar - java

I'm trying to extract 2 jar files from the currently running jar however they always end up at 2kb even though their sizes are 104kb and 1.7m, Heres what I've got
public static boolean extractFromJar(String fileName, String dest) {
if (Configuration.getRunningJarPath() == null) {
return false;
}
File file = new File(dest + fileName);
if (file.exists()) {
return false;
}
if (file.isDirectory()) {
file.mkdir();
return false;
}
try {
JarFile jar = new JarFile(Configuration.getRunningJarPath());
Enumeration<JarEntry> e = jar.entries();
while (e.hasMoreElements()) {
JarEntry je = e.nextElement();
InputStream in = new BufferedInputStream(jar.getInputStream(je));
OutputStream out = new BufferedOutputStream(
new FileOutputStream(file));
copyInputStream(in, out);
}
return true;
} catch (Exception e) {
Methods.debug(e);
return false;
}
}
private final static void copyInputStream(InputStream in, OutputStream out)
throws IOException {
while (in.available() > 0) {
out.write(in.read());
}
out.flush();
out.close();
in.close();
}

This should work better then relying on InputStream.available() method:
private final static void copyInputStream(InputStream in, OutputStream out)
throws IOException {
byte[] buff = new byte[4096];
int n;
while ((n = in.read(buff)) > 0) {
out.write(buff, 0, n);
}
out.flush();
out.close();
in.close();
}

available() method is not reliable to read data as it is just an estimate, as per its documentation.
You need to depend on read() method until read a non -ve.
byte[] contentBytes = new byte[ 4096 ];
int bytesRead = -1;
while ( ( bytesRead = inputStream.read( contentBytes ) ) > 0 )
{
out.write( contentBytes, 0, bytesRead );
} // while available
You can go through a discussion on what the problems with available() is at here.

I'm not sure about extracting jars, but every jar is actually a zip file, so you can try unzip it.
you can findout about unziping in java here:
How to unzip files recursively in Java?

Related

Timing requirements to avoid "Unexpected end of ZLIB input stream"

I have a log analyzing tool that needs to grab *.gz files from Linux servers and unzip them on both Linux and Windows clients. I am getting "Unexpected end of ZLIB input stream" in many instances, which I assume is a difference in detail in the files on Linux and Windows.
Below is my function. It's pretty basic. How do I improved it to prevent the EOF error?
The "in" symbol is a FileInputStream that is created when constructing the class that this function is part of.
public void unzip(File fileTo) throws IOException {
OutputStream out = new FileOutputStream(fileTo);
LOGGER.info("Setting up the file for outputstream : "+fileTo);
try {
in = new GZIPInputStream(in);
byte[] buffer = new byte[65536];
int noRead;
while ((noRead = in.read(buffer)) != -1) {
out.write(buffer, 0, noRead);
}
} finally {
try { out.close(); } catch (Exception e) {}
}
}
I changed from the above to this and now it works. It seems that it was trying to load the output stream before it was done loading the input stream.
public void unzip(File fileTo, String f) throws IOException,
EOFException, InterruptedException {
LOGGER.info("Setting up the file for outputstream : "+fileTo);
GZIPInputStream cIn = new GZIPInputStream(new FileInputStream(f));
OutputStream out = new FileOutputStream(fileTo);
fileTo.setReadable(true, false);
fileTo.setWritable(true, false);
byte[] buffer = new byte[65536];
int noRead;
for (int i = 10; i > 0 && cIn.available() == 1; i--) {
Thread.sleep(1000);
}
try {
while ((noRead = cIn.read(buffer)) != -1) {
out.write(buffer, 0, noRead);
}
} finally {
try { out.close();cIn.close();in.close(); } catch (Exception e) {}
}
}

Error when i am trying to create a zip from 2 files

I am trying to combine 2 files in one zip file
myMainMethod
private void downloadFileByTypeInner(StaticDocument file, String productCode, int productVersion) throws IOException, TechnicalException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
HttpServletResponse response = (HttpServletResponse) ec.getResponse();
String distrib = MultinetFrontHelper.getDefaultDitrib();
String realPath = findRealPath(ec, file.getPath().replace("{DISTRIB}", distrib));
String downloadName = file.getDownloadFileName() != null ? file.getDownloadFileName() : file.getPath();
if (file.getAction() == null || file.getAction().trim().isEmpty() || file.getAction().equals("download")) {
List<java.io.File> l = new ArrayList<>();
java.io.File f = new java.io.File(realPath);
l.add(f);
if(file.getDependOnCodeFiles() != null){
String[] paths = file.getDependOnCodeFiles().split(",");
for (String codefile : paths) {
StaticDocument file2 = libraryBusinessService.getFileByCodeType(codefile, productCode, productVersion);
if((file2 != null)) {
l.add(new java.io.File(findRealPath(ec, file2.getPath())));
}
}
downloadName = downloadName.substring(0,downloadName.lastIndexOf("."))+".zip";
}
InputStream pathStream = DownLoadHelper.getStreamAllFiles(l.toArray(new java.io.File[0]), downloadName);
if (pathStream != null) {
if(downloadName.indexOf('/')!=-1) {
downloadName = downloadName.substring(downloadName.lastIndexOf('/')+1);
}
DownLoadHelper.downLoadFile(response, pathStream, downloadName);
} else {
logger.error("Le fichier " + realPath + " est introuvable!");
throw new TechnicalException(CodeError.CODE_ERTEMO0001, null);
}
} else if (file.getAction().equals("open")) {
final FacesContext ctx = FacesContext.getCurrentInstance();
final ExternalContext extContext = ctx.getExternalContext();
try {
extContext.redirect(file.getPath());
} catch (final IOException ioe) {
throw new FacesException(ioe);
}
}
}
getStreamAllFiles
public static InputStream getStreamAllFiles(final File[] listDoc, String nameZIP) throws IOException {
InputStream stream = null;
if (listDoc != null) {
if (listDoc.length == 1) {
stream = new ByteArrayInputStream(FileUtils.readFileToByteArray(listDoc[0]));
} else if (listDoc.length > 1) {
try( ByteArrayOutputStream baos = new ByteArrayOutputStream();ZipOutputStream zos = new ZipOutputStream(baos)){
for (int i = 0; i < listDoc.length; i++) {
try(InputStream fis = new ByteArrayInputStream(FileUtils.readFileToByteArray(listDoc[i]));BufferedInputStream bis = new BufferedInputStream(fis)){
zos.putNextEntry(new ZipEntry(listDoc[i].getName()));
byte[] bytes = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(bytes)) != -1) {
zos.write(bytes, 0, bytesRead);
}
}
}
zos.closeEntry();
stream = new ByteArrayInputStream(baos.toByteArray());
}
}
}
return stream;
}
downLoadFile
public static void downLoadFile(HttpServletResponse response,InputStream pathStream,String fileName) throws IOException {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition",
"attachment;filename=" + fileName);
ServletOutputStream out = response.getOutputStream();
IOUtils.copyLarge(pathStream, out);
out.flush();
FacesContext.getCurrentInstance().responseComplete();
IOUtils.closeQuietly(pathStream);
IOUtils.closeQuietly(out);
}
I have this error when trying to open the zip file
I presume you're trying to make a zip file with multiple files. The issues are in your getStreamAllFiles method as you don't close the zip entry after putting the content of the file, and you don't close the ZipOutputStream and the end of the loop, so the file loop should look like:
for (int i = 0; i < listDoc.length; i++) {
try(InputStream fis = new ByteArrayInputStream(FileUtils.readFileToByteArray(listDoc[i]));BufferedInputStream bis = new BufferedInputStream(fis)){
zos.putNextEntry(new ZipEntry(listDoc[i].getName()));
byte[] bytes = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(bytes)) != -1) {
zos.write(bytes, 0, bytesRead);
}
zos.closeEntry();
}
}
zos.close();
stream = new ByteArrayInputStream(baos.toByteArray());
i.e. move the zos.closeEntry() inside the loop through the files.
Without moving it inside the listDoc.length loop, if you have more than one file you will not be closing the ZipEntry properly at the end of each entry. You also need to issue a close() on the ZipOutputStream, as otherwise it will not write the end-of-zip directory (which is shown as an error End-of-central-directory signature not found if you test the file under a command line tool.
In addition, I'd move the allocation of the byte buffer outside the file loop as you only need to allocate it once, and reuse the same buffer for all the files you're writing.

Code that download empty file and supposed not to

I have this part of function where it supposed to download file like pdf from server and store in new directory. It does do this but an empty pdf or text file.How to fix it.
`File urlfile = new File(host + "/" + path);
urlfile.getParentFile().mkdirs();
// create outputstream for request and inputstream for data
// download
FileOutputStream outS = new FileOutputStream(urlfile);
DataInputStream instream = new DataInputStream(newsocket.getInputStream());
// get rid of head part to get to actual file
String l = null;
String lastmodtime = null;
boolean done = false;
while (!(l = DAA.readLine()).equals("")) {
if (!done && l.contains("Last-Modified:")) {
lastmodtime = l.substring(l.indexOf(' ') + 1, l.length());
done = true;
System.out.println(l);
}
}
// read in bytes to correct file name
try {
byte[] inbytes = new byte[16384];
int input;
while ((input = instream.read(inbytes)) != -1) {
outS.write(inbytes, 0, input);
}
}`
You can try this simple code if you want to create a copy of the file or you can even use apache commons io (FileUtils.copyFile(source, dest)) for java copy file operation.
private static void copyFileUsingStream(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);
}
} finally {
is.close();
os.close();
}
}

export/zip eclipse project via java program for Windows and MAC

I need to export a (java) eclipse project without using eclipse. I tried to copy all relevant files and pack them with a ZipOutputStream. So good so far, I can load this zip-file in Windows. But MAC users have the problem, that the file structure is not automaticaly detected and create files with names like "vorlage\src\de\tuberlin..." next to the src directory.
(example picture)
Is there a way to properly export an eclipse project with a java programm?
The reason is that I created programming exercises for a lecture and marked the solutions with special comments. During copying the files these comments and the solutions are left out.
One solution would be importing the zip-file in Windos and exporting again with the help of eclipse. But this costs a lot of time doing this for each exercise.
Although I cannot see any difference between the two zip-files, there seems to be something.
Here my code to copy the files:
public static void copyDir(File source, File target, ArrayList<String> exclude)
throws FileNotFoundException, IOException {
File[] files = source.listFiles();
File newFile = null;
target.mkdirs();
if (files != null) {
for (int i = 0; i < files.length; i++) {
newFile = new File(target.getAbsolutePath() + System.getProperty("file.separator") + files[i].getName());
if (files[i].isDirectory()) {
copyDir(files[i], newFile, exclude);
}
else if ( !exclude.contains(files[i].getName()) ) {
copyFile(files[i], newFile);
}
}
}
}
public static void copyFile(File file, File target) throws FileNotFoundException, IOException {
if (file.getName().endsWith(".java")) {
copyJavaFile(file, target);
return;
}
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(target, true));
int bytes = 0;
while ((bytes = in.read()) != -1) {
out.write(bytes);
}
in.close();
out.close();
}
private static void copyJavaFile(File file, File target) throws IOException {
BufferedReader in = new BufferedReader(new FileReader(file));
PrintWriter out = new PrintWriter(target);
boolean stopped = false;
String line = null;
while ( (line = in.readLine() ) != null) {
stopped |= line.contains("IF EXCLUDE");
if (!stopped && !line.contains("ENDIF"))
out.println(line);
stopped &= !line.contains("ELSE");
}
in.close();
out.close();
}
I copy the following (sub-)directories/files:
.settings
src
.classpath
.project
I create the zip-file with:
public Zip(final File projDir, final File outFile) {
ZipOutputStream output = null;
try {
output = new ZipOutputStream(
new BufferedOutputStream(
new FileOutputStream(outFile)));
for (File file : projDir.listFiles()) {
writeFiles(file, output, "");
}
output.finish();
} catch (IOException ex) {
System.err.println("IO Error: " + ex.getMessage());
} finally {
try {output.close();} catch (IOException ex) {}
}
}
private void writeFiles(File f, ZipOutputStream output, String dir) throws IOException {
if (f.isDirectory()) {
// recursively write files in directory
for (File file : f.listFiles()) {
writeFiles(file, output, dir + f.getName() + File.separator);
}
} else {
// write this file to archive
FileInputStream fis = new FileInputStream(f);
ZipEntry entry = new ZipEntry(dir + f.getName());
entry.setTime(f.lastModified());
output.putNextEntry(entry);
copy(fis, output);
output.closeEntry();
fis.close();
}
}
private void copy(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[1024];
int bytes;
while ((bytes = is.read(buffer)) > 0) {
os.write(buffer, 0, bytes);
}
}
It is a problem of the path separator. Using "/" instead of "File.separator" solves the problem.
In the example above the for-loop in the method writeFiles(...) must be:
for (File file : f.listFiles()) {
writeFiles(file, output, dir + f.getName() + "/");
}
See also this answer.

How to return and delete file?

I want to return file (read or load) from method and then remove this file.
public File method() {
File f = loadFile();
f.delete();
return f;
}
But when I delete a file, I delete it from disk and then exists only descriptor to non-existing file on return statement. So what is the most effective way for it.
You can't keep the File handle of deleted file, rather you can keep the data in a byte array temporarily, delete the file and then return the byte array
public byte[] method() {
File f =loadFile();
FileInputStream fis = new FileInputStream(f);
byte[] data = new byte[fis.available()];
fis.read(data);
f.delete();
return data;
}
// Edit Aproach 2
FileInputStream input = new FileInputStream(f);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int bytesRead = input.read(buf);
while (bytesRead != -1) {
baos.write(buf, 0, bytesRead);
bytesRead = input.read(buf);
}
baos.flush();
byte[] bytes = baos.toByteArray();
you can construct the file data from byte array
However, my suggestion is to use IOUtils.toByteArray(InputStream input) from Jakarta commons, why do you want re write when already in plate
Assuming you want to return the file to the browser, this is how I did it :
File pdf = new File("file.pdf");
if (pdf.exists()) {
try {
InputStream inputStream = new FileInputStream(pdf);
httpServletResponse.setContentType("application/pdf");
httpServletResponse.addHeader("content-disposition", "inline;filename=file.pdf");
copy(inputStream, httpServletResponse.getOutputStream());
inputStream.close();
pdf.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
private static int copy(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[512];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}

Categories

Resources