I am trying to write some code that allows me to access a file (specifically EMailBanner.png) that is wrapped as a jar and then included in a war.
The code I have cobbled together is as follows;
public static File getFile(String imagePath){
if(StringUtilities.stringEmptyOrNull(imagePath)){
throw new IllegalArgumentException("Invalid image path");
}
File tempFile = null;
InputStream is = null;
FileOutputStream fos = null;
try{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
is = classLoader.getResourceAsStream(imagePath);
tempFile = File.createTempFile("EMailBanner", ".png");
tempFile.deleteOnExit();
fos = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
}catch(IOException e ){
LOGGER.error("Unable to load image", e);
}catch(Exception e){
LOGGER.error("Unable to load image", e);
}finally{
try {
fos.close();
is.close();
} catch (IOException e) {
LOGGER.warn("Unable to close the file input / file output streams", e);
}
}
return tempFile;
}
The issue I am facing is that when deployed on to the development box as a war file - the application cannot find the png file. If I run locally in eclipse it isn't a problem.
Whats strange is I have a number of properties files in the resources folder as you can see from the image below;
I have no problems loading those from within the jar file - loaded like this;
public static Properties getDatabaseConnectionProps(ApplicationName appName) throws IOException{
if(appName == null){
throw new IllegalArgumentException("Path to proeprties file was null or empty");
}
Properties props = null;
try(InputStream resourceStream = DatabaseUtilities.class.getResourceAsStream("/vimba.properties")) {
if(resourceStream != null){
props = new Properties();
props.load(resourceStream);
return props;
}else{
throw new IllegalArgumentException("In invalid properties file path was provided");
}
} catch (IOException e) {
throw e;
}
}
So why would one approach work and potentially not the other? I am completely out of alternative options so really hope someone can save the day
Thanks
I have just tested something similar on my local machine using your code. It seems to work fine from what I can see.
The only other issue I can see is - if you check the JAR (you can de-compile it), make sure the image you are trying to retrieve is in there and that the filename matches.
Related
I have implement following code to copy file(binary file)
code
private void copyFileWithChannels(File aSourceFile, File aTargetFile) {
log("Copying files with channels.");
FileChannel inChannel = null;
FileChannel outChannel = null;
FileInputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = new FileInputStream(aSourceFile);
inChannel = inStream.getChannel();
outStream = new FileOutputStream(aTargetFile);
outChannel = outStream.getChannel();
long bytesTransferred = 0;
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(0, inChannel.size(), outChannel);
}
}
catch(FileNotFoundException e){
log.error("FileNotFoundException in copyFileWithChannels()",e);
}
catch (IOException e) {
log.error("IOException in copyFileWithChannels()",e);
}
catch (Exception e) {
log.error("Exception in copyFileWithChannels()",e);
}
finally {
try{
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
if (inStream != null) inStream.close();
if (outStream != null) outStream.close();
}catch(Exception e){
log.error("Exception in copyFileWithChannels() while closing the stream",e);
}
}
}
I have test code with one zip file. when i verify file I found that file which generated is corrupt(size was increased).
Source zip file is about 9GB.
Try this:
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(bytesTransferred, inChannel.size() - bytesTransferred, outChannel);
}
Also, I would refer to IOUtils implementation, as a reference
https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/FileUtils.java
specifically
private static void doCopyFile(final File srcFile, final File destFile, final boolean preserveFileDate)
The transferTo method's first argument gives the position from which to transfer, not relative to where the stream left off, but relative to the start of the file. Since you put 0 there it will always transfer from the start of the file. So that line needs to be
bytesTransferred += inChannel.transferTo(bytesTransferred , inChannel.size(), outChannel);
mavarazy mentioned in his answer he's not sure if you need a loop when using inChannel.size(), since the expectation is that if you supply the whole size it will copy the entire file. However, the actual transfer might be less than the requested number of bytes if the output channel's buffer has less room available. So you do need the loop as in his second code snippet.
Unless you have a good reason best to use Files.copy(Path, Path, CopyOption...).
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();
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is it possible to copy database file to SD card?
I have a database on my Android phone, and I need to get the information onto an SD card.
Is it possible to save the database file onto the SD card in a readable state? I haven't been able to find any information on how to do this. I know the name of the database, and fields etc...
I've found some examples that show how to save to SD cards, but not exactly what I need.
Some source code that copies the database file to an SD card would be perfect.
Hopefully this question is clear enough.
Yes. Here is the function that i use:
public void copyDBToSDCard() {
try {
InputStream myInput = new FileInputStream("/data/data/com.myproject/databases/"+DATABASE_NAME);
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/"+DATABASE_NAME);
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
Log.i("FO","File creation failed for " + file);
}
}
OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/"+DATABASE_NAME);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
Log.i("FO","copied");
} catch (Exception e) {
Log.i("FO","exception="+e);
}
}
For a project that I worked on, I put a menu option in the home screen that I could call this function from at any time. Then, I'd move the database to my desktop and open it up with the SQLite Manager plugin for FireFox.
Sure. If this is a database that exists in your app, you can get a reference to the db file via Context.getDatabasePath(), passing it the database name. From there, it's just a routine file copy operation:
//Get a reference to the database
File dbFile = mContext.getDatabasePath("mydb");
//Get a reference to the directory location for the backup
File exportDir = new File(Environment.getExternalStorageDirectory(), "myAppBackups");
if (!exportDir.exists()) {
exportDir.mkdirs();
}
File backup = new File(exportDir, dbFile.getName());
//Check the required operation String command = params[0];
//Attempt file copy
try {
backup.createNewFile();
fileCopy(dbFile, backup);
} catch (IOException e) {
/*Handle File Error*/
}
Where the method fileCopy() is defined as:
private void fileCopy(File source, File dest) throws IOException {
FileChannel inChannel = new FileInputStream(source).getChannel();
FileChannel outChannel = new FileOutputStream(dest).getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
}
}
HTH!
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.
When I run my code and use the files that are in the resource folder of my project itself, I face no problems. It zips the file successfully and I can extract it using WINZIP. The problem comes when I try to zip a file that is not in the project folder.
When I do the same, I am passing the Absolute Path of both the src and the dest files. My program doesn't give any exceptions, but when I try to open that zip file, I get an error saying, File is Invalid.
Can anyone tell me why this may be happening.
public static void compress(String srcPath, String destPath) {
srcFile = new File(srcPath);
destFile = new File(destPath);
try {
fileInputStream = new FileInputStream(srcFile);
fileOutputStream = new FileOutputStream(destFile);
zipEntry = new ZipEntry(srcPath);
zipOutputStream = new ZipOutputStream(fileOutputStream);
zipOutputStream.putNextEntry(zipEntry);
byte[] data = new byte[12];
while ((fileInputStream.read(data)) != -1) {
zipOutputStream.write(data);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try{
fileInputStream.close();
zipOutputStream.close();}catch (Exception e) {
e.printStackTrace();
}
}
}
You should not store paths with drive letters in your zip file because when you try to extract your zip, it will try to create a directory with the name of the drive and fail.
You will need to change your code so that it removes the drive letter from the path before creating the ZipEntry.