Can't delete image which is being used by anoher process - java

i started to use thumbnailator library to make thumbnail in a Spring Boot project
But i'm facing a problem when i try to delete the file, i got an exception telling me the file is being used by another process. I pretty new with Java and i can't figured out where does the problem might come from and what process should i stop/close:
File originalFile = mediaUtils.saveFile(pathOriginal, file);
String path = mediaUtils.resolvePath(imageDir, name, false, image.getCreation());
mediaUtils.saveJPG(originalFile, file.getContentType(), WIDTH_IMAGE_SIZE, path);
String pathThumb = mediaUtils.resolvePath(imageDir, name, true, image.getCreation());
mediaUtils.saveJPG(originalFile, file.getContentType(), WIDTH_IMAGE_SIZE_THUMB, pathThumb);
public File saveFile(String filePath, MultipartFile file) {
try {
Path path = Paths.get(getPath(filePath));
Files.createDirectories(path.getParent());
Files.copy(file.getInputStream(), path);
return new File(path.toString());
} catch (IOException e) {
LOG.error("could not save file", e);
throw new FileException("could not create file: " + getPath(filePath), e);
}
}
private void saveJPG(InputStream imageInputStream, File file, String contentType, int newWidth, String outputPath) {
try {
// verify it is an image
if (!Arrays.asList("image/png", "image/jpeg").contains(contentType)) {
throw new IllegalArgumentException("The file provided is not a valid image or is not supported (should be png or jpeg): " + contentType);
}
// Create input image
BufferedImage inputImage = ImageIO.read(imageInputStream);
newWidth = newWidth > inputImage.getWidth() ? inputImage.getWidth() : newWidth;
double ratio = (double) inputImage.getWidth() / (double) inputImage.getHeight();
int scaledHeight = (int) (newWidth / ratio);
Path path = Paths.get(baseUrl + outputPath + ".jpg");
Thumbnails.of(file)
.size(newWidth, scaledHeight)
.toFile(path.toFile());
LOG.info("writing image to {}", path);
} catch (IOException e) {
LOG.error("could not write image", e);
}
}
Thanks for any advice or help :)

You should make sure to close your inputstreams and files, after you've used them.
Otherwise things like you've mentioned, happen. A process does block your file.
So instead of using simple try-catch-blocks I would recommend to use try-with-resources which will close the underlying streams and files. For example:
try(InputStream imageInputStream = new FileInputStream(...)) {
// do your stuff
}
After the code in the brackets is done or an exception occured, the inputstream will be closed.

Related

Load multiple images with different paths

so i try to load two images from the same path but with different names.
if i copy the path directly from the image everything work fine.
but if i try to build the path from the system only one of them work(img1).
i've try couple of different ways i found in the internet to build the path but the results are the same.
what can cause this problem?
public void loadImages(String nm) {
File f = null;
BufferedImage image = null;
System.out.println("read img:");
String pathName = PICTURE_PATH + this.getMyColor().toString().toLowerCase() + nm;
// read successful this img path.
try {
f = new File(pathName + "North.png");
f.canRead();
System.out.println("\nimg1 path:" + f);
System.out.print("img1 absolute path:" + f.getAbsolutePath());
img1 = ImageIO.read(f);
if (!f.canRead())
throw new IOException("Cant read the first file");
if (!f.exists())
throw new IOException("Cant find the first file");
System.out.println("Successful read img 1");
} catch (IOException e) {
System.out.println("Error:" + e);
}
// got here exception error for this img path.
try {
f = new File(pathName + "East.png");
System.out.println("\nimg2 path:" + f);
System.out.println("img2 absolute path:" + f.getAbsolutePath());
if (!f.canRead())
throw new IOException("Cant read the second file");
if (!f.exists())
throw new IOException("Cant find the second file");
img2 = ImageIO.read(f);
System.out.println("Successful read img 2");
} catch (IOException e) {
System.out.println("Error:" + e);
}
System.out.println("Done.");
}
//this is the relevant output for this function:
//read img:
img1 path:src\icons\‏‏silverCarNorth.png
img1 absolute path:A:\Tools\eclipse\WorkPlace\HW1\src\icons\‏‏silverCarNorth.png
Successful read img 1
img2 path:src\icons\‏‏silverCarEast.png
img2 absolute path:A:\Tools\eclipse\WorkPlace\HW1\src\icons\‏‏silverCarEast.png
Error:java.io.IOException: Cant read the second file
Done.
so its appear the images had some extra characters..
the site not support this kind of characters so i add a print screen from the cmd.
this is the logs from the cmd:
cmd logs
so i had to rename the files and delete the extra characters manually with the windows command line.
and after that everything works just fine!

Using Java to read image from file, and saving it to a different file

I am trying to do the above, but each time, I keep getting the following errorjava.io.FileNotFoundException: file:\C:\Users\User\Desktop\Scrap\main\out\production\resources\ProfilePic\xas.png (The filename, directory name, or volume label syntax is incorrect)
Here's the function I used to do this
private URL url = this.getClass().getResource("/ProfilePic");
public final String PICTURE_DIRECTORY = url.toString();
public String createNewPicture (String path, String newPictureName) {
int width = 12;
int height = 12;
BufferedImage bf = null;
File f = null;
String dst = PICTURE_DIRECTORY +"/"+newPictureName+".png";
try{
f = new File("F://a.jpg");
bf = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
bf = ImageIO.read(f);
System.out.println("read file successfully");
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
dst = PICTURE_DIRECTORY +"/"+newPictureName+".png";
new File (PICTURE_DIRECTORY, newPictureName+".png");
f = new File(dst);
ImageIO.write(bf, "png", f);
//System.out.println("asaas " +dst);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
return dst;
}
Can someone please help me? Spent several hours trying to solve this but stuck. Thanks!
The information you need is found in the error message:
java.io.FileNotFoundException: file:\C:\Users\User\Desktop\Scrap\main\out\production\resources\ProfilePic\xas.png (The filename, directory name, or volume label syntax is incorrect)
The problem in your code is found here:
private URL url = this.getClass().getResource("/ProfilePic");
public final String PICTURE_DIRECTORY = url.toString();
A URL contains a protocol, "file" in your case. The URL class' toString() simply returns the full URL, including protocol.
You now have variable PICTURE_DIRECTORY containing "file:/C:/...". This is not a valid path on any Windows OS.
If you really want to write to a resource (not recommended), you could do:
public final String PICTURE_DIRECTORY = toFile(url).getAbsolutePath();
static private File toFile(final URL url) {
try {
return new File(url.toURI());
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
But note that a resource, as returned by Class..getResource(..), isn't always a file. It could just as well be an entry in a JAR (which you can't write to, in the same way as writing a file).
A better approach would probably be to use a directory relative to your users home directory, or other configured directory.
Finally, as I mentioned in the comments, using ImageIO for copying (image) files is usually the wrong solution. Instead, use Files.copy(...), as in the Copying a File or Directory tutorial.

Transferring a File in android

I have been struggling for two days to try and understand the process of copying a file to the SD card in Android. None of the methods I tried thus far seem to work.
My application has a Profile Picture setting. I need to launch an Intent to pick an Image, then I need to copy the Image to a new Path on the SD Card and then return the Uri of the new Image at which point I check the Images Orientation (Samsung Pics seem to be rotated 90 degrees sometimes). I then rotate the Image correctly and then save the Uri to a SharedPreferences File for use in the Application.
This is my Intent Call:
case R.id.ib_userImage:
i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(i, 1);
break;
This is my current horrific attempt at the copy function, I have changed it so much I am not very lost.
public static void copyImage(Context context, Uri uri) {
Log.i("ATTENTION", "Inside the Copy Function");
Log.i("ATTENTION", "Trying to copy file: " + uri.toString());
try {
String outputPath = Environment.getExternalStorageDirectory() + "/appname/images/";
File dir = new File(outputPath);
if(!dir.exists()) {
dir.mkdirs();
}
Log.i("ATTENTION", "Destination File Created at: " + dir.toURI().toString());
InputStream in = context.getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(dir);
byte[] buffer = new byte[1024];
while(in.read(buffer) > 0) {
out.write(buffer);
}
out.flush();
out.close();
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Log.i("ATTENTION", "File Copied");
}
Thank you for the help, I will provide any other information you might need.
Update:
I am now getting the Following Exception During the Write Process
java.io.FileNotFoundException: /storage/emulated/0/appname/images: open failed: EISDIR (Is a Directory);
My Understaing is that I specified a Directory with the following code:
String outputPath = Environment.getExternalStorageDirectory() + "/medinfo/images/";
File dir = new File(outputPath);
if(!dir.exists()) {
dir.mkdirs();
}
and then passed it to the OutputStream:
OutputStream out = new FileOutputStream(dir);
and the OutputStream would create the file for me within that Directory.
I didn't think that was actually trying to open the Directory.
Usual problem. Don't ignore the count returned by read().
while ((count = in,read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
EDIT Your directory problem is cured by:
dir.getParentFile().mkdirs();
and removing the redundant existence check. At present you are creating the file itself as a directory.

Problems with duplicate filenames when creating via widget

I've got a widget that allows the user to drag and drop an email message or a file into the widget to copy it to their file system. It's the FileExplorer project in OpenNTF, designed by people far more experienced than I am. I want to modify it to provide a new filename if the current filename already exists in the location they're dropping it on. With emails I'd hoped to be able to grab the sender and date, but I've been throwing errors when I try to access the file contents during a drag-and-drop of email.
So, my issue is actually simple. I've got the 'if' to determine if the filename is taken, but I'm overwhelmed trying to figure out how to test multiple options for the filename (like numbering then 'file1.eml', 'file2.eml', 'file3.eml'). I tried, below, inserting the word DUPLICATE, but I'm having no joy.
try {
if (source.isDirectory()) {
File dirTarget = new File(fDest.getAbsoluteFile() + File.separator + source.getName());
if (!dirTarget.exists()) {
dirTarget.mkdir();
}
copyDir(monitor, source, dirTarget);
}
if (source.isFile()) {
File dest = new File(fDest.getAbsolutePath() + File.separator + source.getName());
if (dest.getAbsolutePath().compareTo(source.getAbsolutePath()) != 0) {
copyFile(monitor, source, dest);
} else {
dest = new File(fDest.getAbsolutePath() + File.separator + "DUPLICATE" + File.separator + source.getName());
copyFile(monitor, source, dest);
}
}
} catch (IOException e) {
}
For reference, the copyFile method's parameters are
private void copyFile(IProgressMonitor monitor, File fSource, File fTarget) throws IOException
You need to construct your file name different.
File.seperator
results in / \ or : depending on your platform since it is the char separating the directory from the file.
Since you are dropping a file, you don't need check for the directory, up to you. You need a loop to test file names. To make it easy use (DUPLICATE 1) (DUPLICATE 2) etc. Something like this:
private final static String DUPLICATE = "DUPLICATE";
private void copyOut(File source, File fDest, Monitor monitor) {
try {
if (!source.exists() || !fDest.exists()) {
// one or two files missing, can't copy
// handle error here!
} else {
String destName = fDest.getAbsolutePath()+ File.separator + source.getName();
File dest = new File(destName);
if (source.isDirectory()) {
if (!dest.exists()) {
destPath.mkdirs(); // Fix missing
} else if (dest.isFile()) {
// Raise an error. Destination exists as file source is directory!!!
}
} else { // We checked for existence and dir, so it is a file
// Don't overwrite an existing file
dest = this.checkforDuplicate(dest);
}
copyFile(monitor, source, dest);
}
} catch (IOException e) {
// Error handling missing here!
}
}
private File checkforDuplicate(File dest) {
if (!dest.exists()) {
return dest;
}
int duplicateNum = 1;
while (true) {
ArrayList<String> pieces = Arrays.asList(dest.getAbsolutePath().split("."));
pieces.add(pieces.size()-1, DUPLICATE);
if (duplicateNum > 1) {
pieces.add(pieces.size()-1,Integer.toString(duplicateNum));
}
duplicateNum++;
StringBuilder newName = newStringBuilder();
for (String s : pieces) {
newName.append(s);
newName.append(".");
}
// Strip the last .
String outName = newName.substring(0, newName.length()-2);
File result = new File(outName);
if (!result.exists()) {
return result;
}
}
}
Check the code, written off memory, will contain typos. also doesn't deal with file names that don't contain a dot.

How to copy file inside jar to outside the jar?

I want to copy a file from a jar. The file that I am copying is going to be copied outside the working directory. I have done some tests and all methods I try end up with 0 byte files.
EDIT: I want the copying of the file to be done via a program, not manually.
First of all I want to say that some answers posted before are entirely correct, but I want to give mine, since sometimes we can't use open source libraries under the GPL, or because we are too lazy to download the jar XD or what ever your reason is here is a standalone solution.
The function below copy the resource beside the Jar file:
/**
* Export a resource embedded into a Jar file to the local file path.
*
* #param resourceName ie.: "/SmartLibrary.dll"
* #return The path to the exported resource
* #throws Exception
*/
static public String ExportResource(String resourceName) throws Exception {
InputStream stream = null;
OutputStream resStreamOut = null;
String jarFolder;
try {
stream = ExecutingClass.class.getResourceAsStream(resourceName);//note that each / is a directory down in the "jar tree" been the jar the root of the tree
if(stream == null) {
throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
}
int readBytes;
byte[] buffer = new byte[4096];
jarFolder = new File(ExecutingClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile().getPath().replace('\\', '/');
resStreamOut = new FileOutputStream(jarFolder + resourceName);
while ((readBytes = stream.read(buffer)) > 0) {
resStreamOut.write(buffer, 0, readBytes);
}
} catch (Exception ex) {
throw ex;
} finally {
stream.close();
resStreamOut.close();
}
return jarFolder + resourceName;
}
Just change ExecutingClass to the name of your class, and call it like this:
String fullPath = ExportResource("/myresource.ext");
Edit for Java 7+ (for your convenience)
As answered by GOXR3PLUS and noted by Andy Thomas you can achieve this with:
Files.copy( InputStream in, Path target, CopyOption... options)
See GOXR3PLUS answer for more details
Given your comment about 0-byte files, I have to assume you're trying to do this programmatically, and, given your tags, that you're doing it in Java. If that's true, then just use Class.getResource() to get a URL pointing to the file in your JAR, then Apache Commons IO FileUtils.copyURLToFile() to copy it out to the file system. E.g.:
URL inputUrl = getClass().getResource("/absolute/path/of/source/in/jar/file");
File dest = new File("/path/to/destination/file");
FileUtils.copyURLToFile(inputUrl, dest);
Most likely, the problem with whatever code you have now is that you're (correctly) using a buffered output stream to write to the file but (incorrectly) failing to close it.
Oh, and you should edit your question to clarify exactly how you want to do this (programmatically, not, language, ...)
Faster way to do it with Java 7+ , plus code to get the current directory:
/**
* Copy a file from source to destination.
*
* #param source
* the source
* #param destination
* the destination
* #return True if succeeded , False if not
*/
public static boolean copy(InputStream source , String destination) {
boolean succeess = true;
System.out.println("Copying ->" + source + "\n\tto ->" + destination);
try {
Files.copy(source, Paths.get(destination), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
logger.log(Level.WARNING, "", ex);
succeess = false;
}
return succeess;
}
Testing it (icon.png is an image inside the package image of the application):
copy(getClass().getResourceAsStream("/image/icon.png"),getBasePathForClass(Main.class)+"icon.png");
About the line of code (getBasePathForClass(Main.class)): -> check the answer i have added here :) -> Getting the Current Working Directory in Java
Java 8 (actually FileSystem is there since 1.7) comes with some cool new classes/methods to deal with this. As somebody already mentioned that JAR is basically ZIP file, you could use
final URI jarFileUril = URI.create("jar:file:" + file.toURI().getPath());
final FileSystem fs = FileSystems.newFileSystem(jarFileUri, env);
(See Zip File)
Then you can use one of the convenient methods like:
fs.getPath("filename");
Then you can use Files class
try (final Stream<Path> sources = Files.walk(from)) {
sources.forEach(src -> {
final Path dest = to.resolve(from.relativize(src).toString());
try {
if (Files.isDirectory(from)) {
if (Files.notExists(to)) {
log.trace("Creating directory {}", to);
Files.createDirectories(to);
}
} else {
log.trace("Extracting file {} to {}", from, to);
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
}
} catch (IOException e) {
throw new RuntimeException("Failed to unzip file.", e);
}
});
}
Note: I tried that to unpack JAR files for testing
Robust solution:
public static void copyResource(String res, String dest, Class c) throws IOException {
InputStream src = c.getResourceAsStream(res);
Files.copy(src, Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
}
You can use it like this:
File tempFileGdalZip = File.createTempFile("temp_gdal", ".zip");
copyResource("/gdal.zip", tempFileGdalZip.getAbsolutePath(), this.getClass());
Use the JarInputStream class:
// assuming you already have an InputStream to the jar file..
JarInputStream jis = new JarInputStream( is );
// get the first entry
JarEntry entry = jis.getNextEntry();
// we will loop through all the entries in the jar file
while ( entry != null ) {
// test the entry.getName() against whatever you are looking for, etc
if ( matches ) {
// read from the JarInputStream until the read method returns -1
// ...
// do what ever you want with the read output
// ...
// if you only care about one file, break here
}
// get the next entry
entry = jis.getNextEntry();
}
jis.close();
See also: JarEntry
To copy a file from your jar, to the outside, you need to use the following approach:
Get a InputStream to a the file inside your jar file using getResourceAsStream()
We open our target file using a FileOutputStream
We copy bytes from the input to the output stream
We close our streams to prevent resource leaks
Example code that also contains a variable to not replace the existing values:
public File saveResource(String name) throws IOException {
return saveResource(name, true);
}
public File saveResource(String name, boolean replace) throws IOException {
return saveResource(new File("."), name, replace)
}
public File saveResource(File outputDirectory, String name) throws IOException {
return saveResource(outputDirectory, name, true);
}
public File saveResource(File outputDirectory, String name, boolean replace)
throws IOException {
File out = new File(outputDirectory, name);
if (!replace && out.exists())
return out;
// Step 1:
InputStream resource = this.getClass().getResourceAsStream(name);
if (resource == null)
throw new FileNotFoundException(name + " (resource not found)");
// Step 2 and automatic step 4
try(InputStream in = resource;
OutputStream writer = new BufferedOutputStream(
new FileOutputStream(out))) {
// Step 3
byte[] buffer = new byte[1024 * 4];
int length;
while((length = in.read(buffer)) >= 0) {
writer.write(buffer, 0, length);
}
}
return out;
}
A jar is just a zip file. Unzip it (using whatever method you're comfortable with) and copy the file normally.
${JAVA_HOME}/bin/jar -cvf /path/to.jar

Categories