I'm trying to load image in Java but I'm facing this error:
javax.imageio.IIOException: Can't read input file!
at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1308)
at Main.main(Main.java:10)
This is my code:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Main {
private static BufferedImage tmp;
public static void main(String[] args) {
try {
tmp = ImageIO.read(new File("defaults.png"));
System.out.println("reading completed ");
}catch (IOException e){
System.out.println("Error loading image ");
e.printStackTrace();
}
}
}
This specific error message is thrown when, well, the file can't be read. Check the source code of ImageIO.read():
if (!input.canRead()) {
throw new IIOException("Can't read input file!");
}
It uses the File.canRead() method to check if the file can be read. The documentation from that method say:
Returns:
true if and only if the file specified by this abstract pathname exists and can be read by the application; false otherwise
So the file you are trying to load must exists and the permission must be correct. When the exists() method returns false for your File object you know that the file you are trying to load does not exists (in the working directory you are in). When the file does indeed exists, it is a permission issue that your application are not allowed to read the file.
In a case like this, I would suggest:
Log out the absolute path of the file, to check that the system is looking for it where you think it is looking for it
Try to read the file with one of the newer file API calls (available via the Files class) which will tend to give more clueful errors us to why the file cannot be read:
File f = new File("defaults.png");
System.out.println(f.getAbsolutePath());
try {
Path p = f.toPath();
Files.readAllBytes(p);
} catch (IOException ioex) {
ioex.printStackTrace();
}
Related
Can someone please point out what I'm doing wrong here.
I have a small weather app that generates and sends an HTML email. With my code below, everything works fine when I run it from Eclipse. My email gets generated, it's able to access my image resources and it sends the email with the included attachment.
However, when I build the executable jar by running mvn install and run the jar using java -jar NameOfMyJar.jar I get java.io.FileNotFound Exceptions for my image resource.
I know that I have to be doing something wrong with how I'm accessing my image resources, I just don't understand why it works fine when it's not packaged, but bombs out whenever I package it into a jar.
Any advice is very much appreciated it.
My project layout
How I'm accessing my image resource
//Setup the ATTACHMENTS
MimeBodyPart attachmentsPart = new MimeBodyPart();
try {
attachmentsPart.attachFile("resources/Cloudy_Day.png");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The StackTrace
Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:139)
at Utilities.SendEmailUsingGmailSMTP.SendWeatherEmail(SendEmailUsingGmailSMTP.java:66)
at Weather.Main.start(Main.java:43)
at Weather.Main.main(Main.java:23)
Caused by: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1167)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:134)
... 3 more
Caused by: java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at javax.activation.FileDataSource.getInputStream(FileDataSource.java:97)
at javax.activation.DataHandler.writeTo(DataHandler.java:305)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:865)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:462)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:103)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)
at javax.activation.DataHandler.writeTo(DataHandler.java:317)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1773)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
... 6 more
Others are correct with the use of getResourceAsStream, but the path is a little tricky. You see the little package icon in the resources folder? That signifies that all the files in the resource folder will be put into the root of the classpath. Just like all the packages in src/main/java are put in the root. So you would take out the resources from the path
InputStream is = getClass().getResourceAsStream("/Cloudy_Day.png");
An aside: Maven has a file structure conventions. Class path resources are usually put into src/main/resources. If you create a resources dir in the src/main, Eclipse should automatically pick it up, and create the little package icon for a path src/main/resource that you should see in the project explorer. These files would also go to the root and could be accessed the same way. I would fix the file structure to follow this convention.
Note: A MimeBodyPart, can be Constructed from an InputStream (As suggested by Bill Shannon, this is incorrect). As mentioned in his comment below
"You can also attach the data using"
mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(
this.getClass().getResourceAsStream("/Cloudy_Day.png", "image/png"))));
You can't access resources inside a JAR file as a File, only read them as an InputStream: getResourceAsStream().
As the MimeBodyPart has no attach() method for an InputStream, the easiest way should be to read your resources and write them to temp files, then attach these files.
Try this
new MimeBodyPart().attachFile(new File(this.getClass().getClassLoader().getResource("resources/Cloudy_Day.png").toURI());
I don't know if this will help anyone or not. But, I have a similar case as the OP and I solved the case by finding the file in the classpath using recursive function. The idea is so that when another developer decided to move the resources into another folder/path. It will still be found as long as the name is still the same.
For example, in my work we usually put our resources outside the jar, and then we add said resources path into our classpath, so here the classpath of the resources will be different depending on where it is located.
That's where my code comes to work, no matter where the file is put, as long as it's in the classpath it will be found.
Here is an example of my code in action:
import java.io.File;
public class FindResourcesRecursive {
public File findConfigFile(String paths, String configFilename) {
for (String p : paths.split(File.pathSeparator)) {
File result = findConfigFile(new File(p), configFilename);
if (result != null) {
return result;
}
}
return null;
}
private File findConfigFile(File path, String configFilename) {
if (path.isDirectory()) {
String[] subPaths = path.list();
if (subPaths == null) {
return null;
}
for (String sp : subPaths) {
File subPath = new File(path.getAbsoluteFile() + "/" + sp);
File result = findConfigFile(subPath, configFilename);
if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
return result;
}
}
return null;
} else {
File file = path;
if (file.getName().equalsIgnoreCase(configFilename)) {
return file;
}
return null;
}
}
}
Here I have a test case that is coupled with a file "test.txt" in my test/resources folder. The content of said file is:
A sample file
Now, here is my test case:
import org.junit.Test;
import java.io.*;
import static org.junit.Assert.fail;
public class FindResourcesRecursiveTest {
#Test
public void testFindFile() {
// Here in the test resources I have a file "test.txt"
// Inside it is a string "A sample file"
// My Unit Test will use the class FindResourcesRecursive to find the file and print out the results.
File testFile = new FindResourcesRecursive().findConfigFile(
System.getProperty("java.class.path"),
"test.txt"
);
try (FileInputStream is = new FileInputStream(testFile)) {
int i;
while ((i = is.read()) != -1) {
System.out.print((char) i);
}
System.out.println();
} catch (IOException e) {
fail();
}
}
}
Now, if you run this test, it will print out "A sample file" and the test will be green.
When I run this as a jar, this .properties file is created on the desktop. For the sake of keeping things clean, how can I set the path to save this file somewhere else, like a folder? Or even the jar itself but I was having trouble getting that to work. I plan on giving this to someone and wouldn't want their desktop cluttered in .properties files..
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
public class DataFile {
public static void main(String[] args) {
Properties prop = new Properties();
OutputStream output = null;
try {
output = new FileOutputStream("config.properties");
prop.setProperty("prop1", "000");
prop.setProperty("prop2", "000");
prop.setProperty("prop3", "000");
prop.store(output, null);
} catch (IOException io) {
io.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Since you are using the file name without a path, the file you creates ends in the CWD. That is the Current working directory the process inherits from the OS.
That is is you execute your jar file from the Desktop directory any files that use relative paths will end in the Desktop or any of it sub directories.
To control the absolute location of the file you must use absolute paths.
An absolute path always starts with a slash '/'.
Absolute path:
/etc/config.properties
Relative path:
sub_dir/config.properties
The simplest way is to hard code some path into the file path string.
output = new FileOutputStream("/etc/config.properties");
You can of course setup the path in a property which you can pass using the command line instead of hard coding it. The you concat the path name and the file name together.
String path = "/etc";
String full_path = "/etc" + "/" + "config.properties";
output = new FileOutputStream(full_path);
Please note that windows paths in java use a forward slash instead of back slash.
Check this for more details
file path Windows format to java format
I have used File.createTempFile() method to create temp file but as its output it appends the garbage value with the file name too. I used the method for uploading zipfile, but unable to delete those appended garbage value. For further functionality I need the exact name of file.
Kindly help...
Highly appreciate your response.
My concern is, as code stated by niiraj874u, I am getting the the File name : tmp4501156806082176909.txt
But I want only tmp.txt How can I remove appended numeric value?
You can use java.io.File.getName() method to get name of file..
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
File f = null;
// creates temporary file
try {
f = File.createTempFile("tmp", ".txt", new File("D:/"));
} catch (IOException e) {
e.printStackTrace();
}
// prints name of temp file
System.out.println("File name: "+f.getName());
// prints absolute path
System.out.println("File path: "+f.getAbsolutePath());
}
}
this will print like
File name: tmp4501156806082176909.txt
File path: D:\tmp4501156806082176909.txt
It sounds like you don't need a temp file. The purpose of the "garbage" is to protect two or more instances of the app from overwriting each other. In this case use system.getProperty("java.io.temp") to get the temp dir.
I followed a tutorial to create some simple code to output the contents of a csv file. However, I always get the following message:
java.io.FileNotFoundException: Data.csv (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at java.util.Scanner.<init>(Scanner.java:656)
at testing.csv.files.Test.main(Test.java:26)
BUILD SUCCESSFUL (total time: 0 seconds)
So I guess this means that the program is running, but it can't find my csv file. Basically, I just dragged and dropped it from my desktop into the "Source Packages" file in my Java Project, which is where my Test.java file is. I've also tried putting it in the "testing.csv.files", but that did not work either. Neither did putting it in the "Test Packages".
I've ran out of ideas. Where am I supposed to put this csv file?
here is my code:
package testing.csv.files;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
public static void main(String[] args) {
//.csv comma separated values
String fileName = "Data.csv";
File file = new File(fileName); // TODO: read about File Names
try {
Scanner inputStream = new Scanner(file);
while (inputStream.hasNext()){
String data = inputStream.next();
System.out.println(data);
}
inputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
You could try pointing to the full path of the file.
For example: String fileName = "Desktop/Data.csv";
FYI - You can copy the full path of a file by right clicking on a file while holding shift, then selecting: "copy as path".
Put your csv file(i.e Data.csv) in your project folder then it will work properly i tried your code it works fine for me
This doesn't seem to create a file or folder. Why?
import java.io.*;
public class file1
{
public static void main(String[] args)
{
File text1 = new File("C:/text1.txt");
File dir1 = new File("C:/dir");
}
This one below does create a file.
import java.io.*;
public class file3
{
public static void main(String[] args)
{
try
{
FileWriter text1 = new FileWriter("C:/text.txt");
FileWriter dir = new FileWriter("C:/dir");
}
catch(Exception e){}
}
}
However, the directory seems to have a strange unusable icon.
What can I do to create a directory.
What are other simple methods to create files and folders.
Surprisingly, the File class does not represent a file. It actually represents a pathname for a file ... that may or may not exist.
To create a file in Java, you need to open it for output; e.g.
File text1 = new File("C:/text1.txt");
FileOutputStream os = new FileOutputStream(text1); // The file is created
// here ... if it doesn't
// exist already.
// then write to the file and close it.
or you could do this - new FileOutputStream("C:/text1.txt"). In both cases, an existing file will be truncated ... unless you use the FileOutputStream with a boolean parameter that says open for appending.
If you want to create a file without writing any data to it, you could also do this:
File text1 = new File("C:/text1.txt");
text1.createNewFile();
However, that will only create a new file if the file didn't already exist.
To create a directory in Java, use the File.mkdir() or File.mkdirs() methods.
UPDATE
You commented:
I tried File dir = new File("C:/dir1").mkdir(); it says incompatible types.
That is right. The mkdir() method returns a boolean to say whether or not it created the directory. What you need to write is something like this:
File dir = new File("C:/dir1");
if (dir.mkdir()) {
System.out.println("I created it");
}
Always READ THE JAVADOCS before using a method or class you are not familiar with!
A couple more things you need to know:
The best way to deal with the problem of making sure a file gets closed is to do something like this:
try (FileOutputStream os = new FileOutputStream(text1)) {
// now write to it
}
The stream os will be closed automatically when the block exits.
It is usually "bad practice" to catch Exception. It is always "bad practice" to catch Exception and do nothing in the handler. This kind of this hides the evidence of bugs, and makes your code unpredictable and hard to debug.
If you're creating a directory with File, you want this:
new File("C:/dir").mkdirs();
For creating directory you can use :
if(!text1.exists()){
text1.mkdir();
}
and for creating file use:
if(!text1.exists()){
try {
text1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}