I have an image that I fetch from a url that has no extension(jpg, gif,png, etc).
I have no problem downloading the image.
BufferedImage image = null;
URL url = new URL(link);
image = ImageIO.read(url);
However, I wanted to know the extension of the file before saving to disk. I tried the following and ImageIO.createImageInputStream(image); is always returning null.
ImageInputStream iis = ImageIO.createImageInputStream(image);
//where image is BufferImage but it is always returning null.
while (imageReaders.hasNext()) {
ImageReader reader = imageReaders.next();
System.out.printf("formatName: %s%n", reader.getFormatName());
return ImageFormatTypes.valueOf(reader.getFormatName());
}
Any advice would be appreciated.
Once you create a java.awt.Image, there is no format. It's not a PNG, it's not a JPEG, it's just a Java Image. So you cannot get the image format from your Image object.
You need to get it from the URL. The most reliable way is to check the URL's content type, then get the extension from the ImageIO provider:
URL url = new URL(link);
URLConnection conn = url.openConnection();
String contentType = conn.getContentType();
String suffix = null;
Iterator<ImageReader> readers =
ImageIO.getImageReadersByMIMEType(contentType);
while (suffix == null && readers.hasNext()) {
ImageReaderSpi provider = readers.next().getOriginatingProvider();
if (provider != null) {
String[] suffixes = provider.getFileSuffixes();
if (suffixes != null) {
suffix = suffixes[0];
}
}
}
You can also save the URL to a temporary file, so you can use Files.probeContentType on it:
URL url = new URL(link);
Path imageFile = Files.createTempFile("image", null);
try (InputStream stream = url.openStream()) {
Files.copy(stream, imageFile, StandardCopyOption.REPLACE_EXISTING);
}
image = ImageIO.read(imageFile.toFile());
String contentType = Files.probeContentType(imageFile);
Files.delete(imageFile);
But you'll still need ImageIO providers to get an extension from a MIME type.
In Java 7+ you can now just use Files.probeContentType(path).
----------
public static String probeContentType(Path path)
throws IOException
Probes the content type of a file.
This method uses the installed FileTypeDetector implementations to
probe the given file to determine its content type. Each file type
detector's probeContentType is invoked, in turn, to probe the file
type. If the file is recognized then the content type is returned. If
the file is not recognized by any of the installed file type detectors
then a system-default file type detector is invoked to guess the
content type.
A given invocation of the Java virtual machine maintains a system-wide
list of file type detectors. Installed file type detectors are loaded
using the service-provider loading facility defined by the
ServiceLoader class. Installed file type detectors are loaded using
the system class loader. If the system class loader cannot be found
then the extension class loader is used; If the extension class loader
cannot be found then the bootstrap class loader is used. File type
detectors are typically installed by placing them in a JAR file on the
application class path or in the extension directory, the JAR file
contains a provider-configuration file named
java.nio.file.spi.FileTypeDetector in the resource directory
META-INF/services, and the file lists one or more fully-qualified
names of concrete subclass of FileTypeDetector that have a zero
argument constructor. If the process of locating or instantiating the
installed file type detectors fails then an unspecified error is
thrown. The ordering that installed providers are located is
implementation specific.
The return value of this method is the string form of the value of a
Multipurpose Internet Mail Extension (MIME) content type as defined by
RFC 2045: Multipurpose Internet Mail Extensions (MIME) Part One:
Format of Internet Message Bodies. The string is guaranteed to be
parsable according to the grammar in the RFC.
Related
I have a jar file on disk that I want to connect to as a JarURLConnection. The problem is that when I open it as a File it is of URI type file:.
System.out.println(new java.io.File("test.jar").toURI().toURL());
Output:
file:/C:/path/test.jar
If I have only a string path to the file on disk, do I need to identify the URI type myself or is there a way to derive it at some point in processing?
I was planning to test whether it was a jar file like this:
URLConnection urlc = new java.io.File(jarPath).toURI().toURL().openConnection();
if (!(urlc instanceof JarURLConnection))
throw new IOException("File type is not a jar");
But the URI isn't a jar:file: at this point.
How do I set the URI type of a File? And is this the correct procedure when opening a connection to a jar file?
From the javadoc of JarURLConnection:
URL url = new URL("jar:file:/home/duke/duke.jar!/");
JarURLConnection jarConnection = (JarURLConnection)url.openConnection();
In my application I load resources in this manner:
WinProcessor.class.getResource("repository").toString();
and this gives me:
file:/root/app/repository (and I replace "file:" with empty string)
This works fine when I run my application from the IDE, but when I run the jar of my application:
java -jar app.jar
The path becomes:
jar:/root/app.jar!/repository
is there any way to solve this problem?
I'll use the "repository" dir name in order to create this:
ConfigurationContext ctx = (ConfigurationContext) ConfigurationContextFactory.createConfigurationContextFromFileSystem(repositoryString, null);
In the same manner, I'll get one file name (instead of a dir) and I'll use it this way:
System.setProperty("javax.net.ssl.trustStore", fileNameString)
It sounds like you're then trying to load the resource using a FileInputStream or something like that. Don't do that: instead of calling getResource, call getResourceAsStream and read the data from that.
(You could load the resources from the URL instead, but calling getResourceAsStream is a bit more convenient.)
EDIT: Having seen your updated answer, it seems other bits of code rely on the data being in a physical single file in the file system. The answer is therefore not to bundle it in a jar file in the first place. You could check whether it's in a separate file, and if not extract it to a temporary file, but that's pretty hacky IMO.
When running code using java -jar app.jar, java uses ONLY the class path defined in the manifest of the JAR file (i.e. Class-Path attribute). If the class is in app.jar, or the class is in the class path set in the Class-Path attribute of the JAR's manifest, you can load that class using the following code snippet, where the className is the fully-qualified class name.
final String classAsPath = className.replace('.', '/') + ".class";
final InputStream input = ClassLoader.getSystemResourceAsStream( path/to/class );
Now if the class is not part of the JAR, and it isn't in the manifest's Class-Path, then the class loader won't find it. Instead, you can use the URLClassLoader, with some care to deal with differences between windows and Unix/Linux/MacOSX.
// the class to load
final String classAsPath = className.replace('.', '/') + ".class";
// the URL to the `app.jar` file (Windows and Unix/Linux/MacOSX below)
final URL url = new URL( "file", null, "///C:/Users/diffusive/app.jar" );
//final URL url = new URL( "file", null, "/Users/diffusive/app.jar" );
// create the class loader with the JAR file
final URLClassLoader urlClassLoader = new URLClassLoader( new URL[] { url } );
// grab the resource, through, this time from the `URLClassLoader` object
// rather than from the `ClassLoader` class
final InputStream input = urlClassLoader.getResourceAsStream( classAsPath );
In both examples you'll need to deal with the exceptions, and the fact that the input stream is null if the resource can't be found. Also, if you need to get the InputStream into a byte[], you can use Apache's commons IOUtils.toByteArray(...). And, if you then want a Class, you can use the class loader's defineClass(...) method, which accepts the byte[].
You can find this code in a ClassLoaderUtils class in the Diffusive source code, which you can find on SourceForge at github.com/robphilipp/diffusive
And a method to create URL for Windows and Unix/Linux/MacOSX from relative and absolute paths in RestfulDiffuserManagerResource.createJarClassPath(...)
Construct a URL, you can then load a resource (even in a jar file) using the openStream method.
I've implemented a class to read from RSS 2.0 and Atom 1.0 feeds. I want to write some unit tests in order to verify functionality. Here is the feed reader section of my code:
private String readFeed(final String url) throws IOException
{
final StringBuilder builder = new StringBuilder();
final URL feedUrl = new URL(url);
final BufferedReader in = new BufferedReader(
new InputStreamReader(feedUrl.openStream()));
String input;
while ((input = in.readLine()) != null)
{
builder.append(input);
}
in.close();
return builder.toString();
}
After some research, I figured the best way to test would be to have a sample feed as an XML file in my project resources directory.
I've created a example file "resources/rss2-0.xml"
I'm sending in the following value to the readFeed function, "resource:///rss2-0.xml",
and I keep receiving java.net.MalformedURLException: unknown protocol: resource
This is my first time using a URL pathway to load from a resource. From what I can tell, resource seems like it should be a valid protocol. Anyone have any ideas what I may be doing wrong or other ways to go about this?
If you want to deal with path using your local file system, the Path class is best suited for this task.
An object that may be used to locate a file in a file system. It will
typically represent a system dependent file path.
You can use it like so :
Path path = FileSystems.getDefault().getPath("/resources/rss2-0.xml");
BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
If your really want to deal with URL, the protocol you're looking for is simply "file". So it would be file:///rss2-0.xml instead of resource:///rss2-0.xml and even file:/resources/rss2-0.xml to be exact.
Note that in your case, you will indeed have to deal with URLs sooner or later, but when working on local tests, using the Path class will save you troubles. If you want another alternative, try the URI class. Since an URI is an identifier (see difference between URI and URL) it can identify either an URL or a Path an may serve as a bridge between your production code which will ultimately deal with URLs and your test code where the Path class could be best put in use.
For example :
public interface FeedReader {
String readFeed(final URI uri);
}
And 2 implementations, one for testing locally :
public class LocalFeedReader implements FeedReader {
#Override
public String readFeed(final URI uri) {
// URI -> Path
// then dealing with Path to target local rss2-0.xml file
}
}
And one for production code :
public class WebFeedReader implements FeedReader {
#Override
public String readFeed(final URI uri) {
// URI -> URL
// then dealing with URL to target real resources
}
}
The java docs say that only http, https, file, and jar are "guaranteed" to exist on the search path for protocol handlers. Others only "may" be supported.
http://docs.oracle.com/javase/8/docs/api/java/net/URL.html#URL-java.lang.String-java.lang.String-int-java.lang.String-
It looks like if you want a custom handler that isn't supported in your java distribution, you'll have to create one.
http://mjremijan.blogspot.com/2012/02/create-your-own-java-url-handlers.html
Is it possible to get and set custom metadata on File instances? I want to use the files that I process through my system as some kind of a very simple database, where every file should contain additional custom metadata, such as the email of the sender, some timestamps, etc.
It is for an internal system, so security is not an issue.
In java 7 you can do this using the Path class and UserDefinedFileAttributeView.
Here is the example taken from there:
A file's MIME type can be stored as a user-defined attribute by using this code snippet:
Path file = ...;
UserDefinedFileAttributeView view = Files
.getFileAttributeView(file, UserDefinedFileAttributeView.class);
view.write("user.mimetype",
Charset.defaultCharset().encode("text/html");
To read the MIME type attribute, you would use this code snippet:
Path file = ...;
UserDefinedFileAttributeView view = Files
.getFileAttributeView(file,UserDefinedFileAttributeView.class);
String name = "user.mimetype";
ByteBuffer buf = ByteBuffer.allocate(view.size(name));
view.read(name, buf);
buf.flip();
String value = Charset.defaultCharset().decode(buf).toString();
You should always check if the filesystem supports UserDefinedFileAttributeView for the specific file you want to set
You can simply invoke this
Files.getFileStore(Paths.get(path_to_file))).supportsFileAttributeView(UserDefinedFileAttributeView.class);
From my experience, the UserDefinedFileAttributeView is not supported in FAT* and HFS+ (for MAC) filesystems
I am using some file IO and want to know if there is a method to check if a file is an image?
This works pretty well for me. Hope I could help
import javax.activation.MimetypesFileTypeMap;
import java.io.File;
class Untitled {
public static void main(String[] args) {
String filepath = "/the/file/path/image.jpg";
File f = new File(filepath);
String mimetype= new MimetypesFileTypeMap().getContentType(f);
String type = mimetype.split("/")[0];
if(type.equals("image"))
System.out.println("It's an image");
else
System.out.println("It's NOT an image");
}
}
if( ImageIO.read(*here your input stream*) == null)
*IS NOT IMAGE*
And also there is an answer: How to check a uploaded file whether it is a image or other file?
In Java 7, there is the java.nio.file.Files.probeContentType() method. On Windows, this uses the file extension and the registry (it does not probe the file content). You can then check the second part of the MIME type and check whether it is in the form <X>/image.
You may try something like this:
String pathname="abc\xyz.png"
File file=new File(pathname);
String mimetype = Files.probeContentType(file.toPath());
//mimetype should be something like "image/png"
if (mimetype != null && mimetype.split("/")[0].equals("image")) {
System.out.println("it is an image");
}
You may try something like this:
import javax.activation.MimetypesFileTypeMap;
File myFile;
String mimeType = new MimetypesFileTypeMap().getContentType( myFile ));
// mimeType should now be something like "image/png"
if(mimeType.substring(0,5).equalsIgnoreCase("image")){
// its an image
}
this should work, although it doesn't seem to be the most elegant version.
There are a variety of ways to do this; see other answers and the links to related questions. (The Java 7 approach seems the most attractive to me, because it uses platform specific conventions by default, and you can supply your own scheme for file type determination.)
However, I'd just like to point out that no mechanism is entirely infallible:
Methods that rely on the file suffix will be tricked if the suffix is non-standard or wrong.
Methods that rely on file attributes (e.g. in the file system) will be tricked if the file has an incorrect content type attribute or none at all.
Methods that rely on looking at the file signature can be tricked by binary files which just happen to have the same signature bytes.
Even simply attempting to read the file as an image can be tricked if you are unlucky ... depending on the image format(s) that you try.
Other answers suggest to load full image into memory (ImageIO.read) or to use standard JDK methods (MimetypesFileTypeMap and Files.probeContentType).
First way is not efficient if read image is not required and all you really want is to test if it is an image or not (and maybe to save it's content type to set it in Content-Type response header when this image will be read in the future).
Inbound JDK ways usually just test file extension and not really give you result that you can trust.
The way that works for me is to use Apache Tika library.
private final Tika tika = new Tika();
private MimeType detectImageContentType(InputStream inputStream, String fileExtension) {
Assert.notNull(inputStream, "InputStream must not be null");
String fileName = fileExtension != null ? "image." + fileExtension : "image";
MimeType detectedContentType = MimeType.valueOf(tika.detect(inputStream, fileName));
log.trace("Detected image content type: {}", detectedContentType);
if (!validMimeTypes.contains(detectedContentType)) {
throw new InvalidImageContentTypeException(detectedContentType);
}
return detectedContentType;
}
The type detection is based on the content of the given document stream and the name of the document. Only a limited number of bytes are read from the stream.
I pass fileExtension just as a hint for the Tika. It works without it. But according to documentation it helps to detect better in some cases.
The main advantage of this method compared to ImageIO.read is that Tika doesn't read full file into memory - only first bytes.
The main advantage compared to JDK's MimetypesFileTypeMap and Files.probeContentType is that Tika really reads first bytes of the file while JDK only checks file extension in current implementation.
TLDR
If you plan to do something with read image (like resize/crop/rotate it), then use ImageIO.read from Krystian's answer.
If you just want to check (and maybe store) real Content-Type, then use Tika (this answer).
If you work in the trusted environment and you are 100% sure that file extension is correct, then use Files.probeContentType from prunge's Answer.
Here's my code based on the answer using tika.
private static final Tika TIKA = new Tika();
public boolean isImageMimeType(File src) {
try (FileInputStream fis = new FileInputStream(src)) {
String mime = TIKA.detect(fis, src.getName());
return mime.contains("/")
&& mime.split("/")[0].equalsIgnoreCase("image");
} catch (IOException e) {
throw new RuntimeException(e);
}
}