Is there any reason not to use resource.getInputStream()? - java

Is it ever favorable to create a FileInputStream, like this:
InputStream fileInputStream = new FileInputStream(resource.getFile());
instead of using the InputStream created by the resource, like this:
InputStream resourceInputStream = resource.getInputStream();
The resource is an org.springframework.core.io.Resource.

A resource does not always come from a File. It may come from a network resource or be dynamically generated by the class loader. If you do that you may be fine 99% of the time, but you could have trouble in specific unexpected situations.
As a general rule it's better not to make assumptions about the concrete implementation of anything.
By using resource.getFile() your making the assumption that the resource comes from a file.

If all you need is the input stream, then there is no reason not to use it. The point of getFile is getting access to the file in ways other than opening a FileInputStream on it, such as reading attributes, moving, deleting, opening it through NIO instead of classic IO, etc.

Related

Does creating a new File object in Java use up memory? [duplicate]

While java.io.RandomAccessFile does have a close() method java.io.File doesn't. Why is that? Is the file closed automatically on finalization or something?
The javadoc of the File class describes the class as:
An abstract representation of file and directory pathnames.
File is only a representation of a pathname, with a few methods concerning the filesystem (like exists()) and directory handling but actual streaming input and output is done elsewhere. Streams can be opened and closed, files cannot.
(My personal opinion is that it's rather unfortunate that Sun then went on to create RandomAccessFile, causing much confusion with its inconsistent naming.)
java.io.File doesn't represent an open file, it represents a path in the filesystem. Therefore having close method on it doesn't make sense.
Actually, this class was misnamed by the library authors, it should be called something like Path.
Essentially random access file wraps input and output streams in order to manage the random access. You don't open and close a file, you open and close streams to a file.
A BufferedReader can be opened and closed but a File is never opened, it just represents a path in the filesystem.
Say suppose, you have
File f = new File("SomeFile");
f.length();
You need not close the Files, because its just the representation of a path.
You should always consider to close only reader/writers and in fact streams.
As already stated, the File class does not have a closing method as it's merely a path or a reference to the actual File.
You will usually use this File class as a helper to open the actual file with a FileReader class which you can close. That said, it does close itself on exit but if you read a file from your program and then try to do something to this file externally, it could result in an error on that external call, so it's better to close it
File path = new File(/some/path/file.txt);
FileReader actualFile = new FileReader(path);
...<
if(imDoneWithTheFile)
actualFile.close();

java I/O try with resources for binary data parameters?

I'm rather confused on the parameters for reading and writing binary data.
When reading and writing bytes containing ASCII caharacters I understand the format is something like this try(FileInputStream fin = new FileInputStream(args[0])) . Where its mostly console arguments.
But I see that for the try with resources in reading and writing binary data its
try(DataInputStream dataIn = new DataInputStream(new FileInputStream("testdata"))) &
try(DataOutputStream dataOut = new DataOutputStream(new FileOutputStream("testdata"))
Why is new FileInputStream("testdata") written like this ? Why is it created as an object inside and what is "testdata" suppose to mean ?
I/O libraries can be very confusing because different communications have different needs. The architecture is intended to keep as much in common as possible. The various subclasses and wrapper classes either add characteristics (such as buffering) or processing (such as text encoding/decoding or datatype transformations).
(Sometimes it seems like the architecture is too fractured because each class adds so little and it takes two or three classes to do very common things. Commonly used 3rd-party libraries can make it easier.)
Think of it this way, if the object you have is awkward in some way, find the class in the library that makes it easier to use in the way you need. You haven't shown any code that does anything so I can't point to a specific advantage to using the classes that you mention.
"testdata" would be the name of what your operating system presents to your user's Java as a "file". In the common case, it is the name of a file, in what would be the current working directory for your program. Which directory that is might depend on how your users start your program. (Perhaps you are expecting a file name to have an extension."
Tip: Use an IDE that presents JavaDoc
Tip: Use an IDE that allows refactoring, particularly, extract local variable. That gives you a chance to pull out expressions that are confusing to you and give them a name.

Not able to write to file - java

Pretty sure this should be really easy, but I can't write to a file. No I/O exception is thrown nothing. I was having a similar problem reading earlier and I tried a hundred different ways until
DataInputStream dis = new DataInputStream(reading.class.getResourceAsStream("hello.txt");
BufferedReader input = new BufferedReader(new InputStreamreader(dis));
this worked! and I could use scanners and such to read from this point.
FileReader, making File file = new File("hello.txt") whatever, none of that worked. I couldn't get any of it to even throw an error when it was an incorrect file name.
Now I have the same problem except for writing to a file but there's no equivilant to
reading.class.getResourceAsStream("hello.txt"); that makes an /output/ stream.
Does anyone know how to get the "ResourceAsStream" but as an output stream, /or/ does anyone know what my problem might be?
I know a lot of people on this website have reading/writing issues but none of the posts helped me.
note - yes I was closing, yes I was flushing, yes I had code that wrote to the file.
GetResourceAsStream is meant to read resources (e.g. property files) that were distributed and packages along with the code. There's no guarantee they're in writable mode, e.g. both code and resources could be distributed as a jar, or jar-inside-a-WAR-inside-an-EAR...
See here Write to a file stream returned from getResourceAsStream() for additional discussion and a workaround suggestion, though it's not very recommended IMHO. I think the reasonable practice is to distinguish between (a) your immutable code distribution (b) data editable at runtime ... the latter could reside on a different machine, have different policies for secuirty/replicatoin/backup, etc.

Is there a way to tell if a classpath resource is a file or a directory?

For example, this snippet throws a NullPointerException(!) on the stream.read() line, assuming the com.google package exists in a JAR somewhere (Guava, for example).
ClassLoader classLoader = getClass().getClassLoader();
URL resource = classLoader.getResource("com/google");
InputStream stream = resource.openStream();
System.out.println(stream.toString()); // Fine -- stream is not null
stream.read(); // NPE inside FilterInputStream.read()!
If com/google is swapped with a package that's in the file system rather than a JAR, then the snippet doesn't crash at all. In fact, it seems to read the files in that directory, separated by newlines, though I can't imagine that behaviour is specified anywhere.
Is there a way test if the resource path "com/google" points to a "normal" resource file or to a directory?
This is a bit of a mess due to some unspecified behaviour for the protocol handlers involved in loading these resources. In this particular situation, there are two: sun.net.www.protocol.file.Handler and sun.net.www.protocol.jar.Handler, and they each handle the directory case a bit differently. Based on some experiments, here's what they each do:
sun.net.www.protocol.file.Handler:
What this Handler does is open a FileURLConnection, which does exactly what you discovered it did when confronted with a directory. You can check if it's a directory just with:
if (resource.getProtocol().equals("file")) {
return new File(resource.getPath()).isDirectory();
}
sun.net.www.protocol.jar.Handler:
This Handler, on the other hand, opens a JarURLConnection which eventually makes its way to a ZipCoder. If you take a look at that code, you'll notice something interesting: jzentry will come back null from the native JNI call because the JAR zip file does not, in fact, contain a file called com/google, and so it returns null to the stream that wraps it.
However, there is a solution. Although the ZipCoder won't find com/google, it will find com/google/ (this is how most ZIP interfaces work, for some reason). In that case, the jzentry will be found, and it'll just return a null byte.
So, cutting through all these random implementation-specific behaviours, you can probably figure out if it's a directory by first trying to access the resource with a trailing / (which is what URLClassLoaders expect for directories anyway). If ClassLoader.getResource() returns non-null, then it's a directory. If it doesn't, try without the trailing slash. If it returns non-null, it's a file. If it still returns null, then it's not even an existing resource.
Kinda hacky, but I don't think there's anything better. I hope this helps!
There is no safe and generic way to detect this. When you use ClassLoader.getResource(), the ClassLoader can return practically anything in the URL, in principle even something you have never seen before if the ClassLoader implements its own URL scheme (and protocol).
Your only option is to analyze the URL returned by getResource(), the protocol should hint at what it is (e.g. "file://"). But beware, depending on environment it may return things you did not plan for.
But to just access a resource, you don't care where it comes from (you may care if you're debugging a configuration issue, but your code should not care).
In general you should not make assumptions about the returned InputStream's capabilities, i.e. do not rely on it supporting mark/reset etc. The only safe operation would be simply reading the Stream. If an IOException occurs during read it indicates a problem with access to the resource (network connection lost etc.).
EDIT: getResource() should IMO only return resources (e.g. files or zip file entries), but never directories (since they are not resources). However I wouldn't count on every possible ClassLoader to do so, and I'm not sure what the correct behavior is (if its even specified somewhere).
I think that there are 2 solutions.
Naive solution based on analysis of the path itself. If it ends with .jar or .zip or .war or .ear it is a file. Otherwise it is a directory. I think that this approach will work in 99.99% of cases unless somebody tries to make you you to fail on purpose. For example by defining soft link that looks like a directory but is a file or vise versa.
Try to mimic the JVM logic that interprets paths of classpath relatively to the current working directory. So, retrieve current working directory by using new File("."), then take classpath, split it and for each its element use new File(".", classPathElement) unless it is defined using absolute path.
Good luck with this.

Managing file bytes with DataOutput/InputStream

I have a program that will go through and create multiple different class instances. I want to write the details of each instance to a file using DataOutputStream (it's a necessary exercise, I'll look at other ways of doing this later), but the problem is I noticed that DataOutputStream overwrites the file each time a new instance is created and written. My first idea was each time a new instance is written, first using DataInputStream to get what's in the file, save it, and then rewrite it with the new instance. This seems like it could get confusing very fast. What would be best practice for something like this? Thanks in advance.
EDIT: I will try and be a bit more specific about what I'm trying to do here.
When I take the class that I want to write to the file, first I'll use an dataInputStream.readFully to get everything in the file. My understanding is that takes all the bytes in the file and stores them in an array. I would like to compare this with the class instance and if the instance matches something already in the file, don't output this particular instance (because it's already there) to the file. Otherwise, append to the file.
Use the FileOutputStream(File file, boolean append) constructor when you open the file for writing. For example:
File f = new File("C:\data.txt");
FileOutputStream fos = new FileOutputStream(f, true); // open file for appending
DataOutputStream dos = new DataOutputStream(fos);
// anything written to dos after this point will be appended
If you just need to serialize your objects, I'd highly recommend using JAXB or another serialization/marshaling API instead of reinventing the wheel. You'll potentially save a ton of time.

Categories

Resources