InputStream in java - java

How to get InputStream and size of File type in servlet?
Previously i was using FileUpload type which has getInputStream() and getSize() methods, but now i have to use File type for bulk upload. I have tried but File type has no such methods.

Use File#length() to get the size.
long size = file.length();
// ...
Use FileInputStream constructor to create an InputStream based on a given File.
InputStream input = new FileInputStream(file);
// ...
See also the File javadoc and the basic Java I/O tutorial.

Related

classLoader.getResourceAsStream returns an empty Stream in Testing

I have a method where I need to read a resource file and pass it to another method as an InputStream. The obvious approach
InputStream is = classLoader.getResourceAsStream("filename.pem");
works fine when actually running the application, but in testing it returns an empty InputStream (filled with zeros). I don't think its a problem with the resource path or anything, because when I use a nonsense path like "filex" (filex does not exist), I get an actual null pointer exception and not an empty stream. Also in debugger the complete file path of the empty Stream points to the correct path, where the file actually is stored (default class root).
Furthermore, with the following workaround it works:
File file = new File(classLoader.getResource("filename.pem").getFile());
String fileS= new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
InputStream is = classLoader.getResourceAsStream("filename.pem");
InputStream is2 = new ByteArrayInputStream(fileS.getBytes(StandardCharsets.UTF_8));
In this example is2 has the actual content of the file in the InputStream, while is has an Stream filled with zeros. I can't quite explain that behaviour. I double checked with 'getClass().getClassLoader().getClass()' if we use some modified ClassLoader in the Application, but it is the original one from sun.misc.Launcher$AppClassLoader.
So my questions are:
Why does the workaround work but not the classic approach?
Why does it fail only in test class?
Is there a way to make it work? The workaround is more lines of code and also need to catch IOException because of the Files.readAllBytes() call.
The only idea I had left: the encoding or charset has something to do with it. But to my knowledge there is no parameter in getResourceAsStream() like Charset or StandardCharsets.
If you open a resource file as a stream, you end up with a BufferedInputStream around a FileInputStream.
The call chain is as follows:
java.lang.ClassLoader#getResource returns an URL
url.openStream() is called
this first opens the Stream; sun.net.www.protocol.file.Handler#createFileURLConnection
then the Stream is connected: is = new BufferedInputStream(new FileInputStream(filename)); in sun.net.www.protocol.file.FileURLConnection#connect
finally you get this is back as InputStream
What you're seeing is the empty internal buffer of the BufferedInputStream, which will be used as soon as you start reading from the InputStream.
See is FileInputStream not buffered and why BufferedInputStream is faster?
If you for example read from the InputStream with all zero's, you will see it does actually contain data:
Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name());
String firstLine = scanner.next();
From https://www.baeldung.com/convert-input-stream-to-string
Your workaround works, because after you've located the file from the resource URL you actually start reading it directly.
So what might be failing in your test; are you not trying to read from the stream in your testcase? How are you using/validating if this inputstream is correct in your test vs the real application? There might be the problem.

FileItem inputStream to FileInputStream

I have a web page with an upload feature which lets you upload a excel file, on hitting upload an Ajax call is fired. From there I get the FileItem input stream and using the method fileItem.getInputStream(), I have another class with a method which I need to pass the file to, which has a FileInputStream parameter. So my question is how do I convert the input stream to a FileInputStream?
A detailed solution would be appreciated as I am a junior developer, so I am still learning.
Many thanks.
From JavaDoc
A FileInputStream obtains input bytes from a file in a file system.
I would suggest two solutions:
The proper one is to change the API and to have InputStream as a parameter. I don't see a reason why you have FileInputStream in your API.
If you don't own the API and cannot change it I'm afraid you will need to save the InputStream to temp file and then create FileInputStream giving a path to this file (it's a suboptimal solution as you first write the file to disk - risking out of space - and then read it and streaming API is designed for reading / writing data on the fly)
If you are using org.apache.commons.fileupload.FileItem interface then your class is probably DefaultFileItem which is a subclass of DiskFileItem. So you can cast FileItem to DiskFileItem. then if you look at the source code of DiskFileItem you'll find that getInputStream() is actually returning a FileInputStream or a ByteArrayInputStream If you get a FileInputStream from DiskFileItem you can pass it directly to your other class. But if you get a ByteArrayInputStream you will have to write the contents to your own temporary file and then open another FileInputStream on this temp file. There is also another method DiskFileItem.getStoreLocation() which seem to return the server side File used for upload, but it may return null if the file is cached in memory.
In conclusion: you cannot be sure that there is going to be a server side file because the upload may be cached in memory. Therefore if you need a FileInputStream elsewhere you will have to create it yourself by creating a temp file. There is an example on how to pipe between two streams here.
//Pass file path/name directly to FileInputStream
FileInputStream input1 = new FileInputStream("input.txt");
//Save file path that has been passed in by the user, into a string variable.
String fileName = args[0];
//pass path to File object
File inputFile = new File(fileName);
//pass file object to FileOutputStream
FileOutputStream output = new FileOutputStream(inputFile);

Need to convert AssetInputStream to FileInputStream

I have implemented a data structure which is working on my computer and now I am trying to port it into my android application. I open a raw .dat resource and get a InputStream but I need to get a FileInputStream:
FileInputStream fip = (FileInputStream) context.getResources().openRawResource(fileID);
FileChannel fc = fip.getChannel();
long bytesSizeOfFileChannel = fc.size();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0L, bytesSizeOfFileChannel);
...
The code above throws the following exception since an InputStream can not be cast to a FileInputStream but that's just what I need:
java.lang.ClassCastException: android.content.res.AssetManager$AssetInputStream cannot be cast to java.io.FileInputStream
All my code is build on using this FileChannel with a FileInputStream so I want to keep using it. Is there a way to go from having an InputStream from context.getResources().openRawResource(fileID) and then convert it into a FileChannel?
Somewhat relevant posts in which I could not find a working solution for my case which android:
How to convert InputStream to FileInputStream
Converting inputStream to FileInputStream?
Using FileChannel to write any InputStream?
A resource isn't a file. Ergo it can't be used as a memory-mapped file. If you have resources that are so enormous they need to be memory-mapped, they probably shouldn't be resources at all. And if they are small, memory mapping brings no advantages.
This might be late, but i think you can indirectly get a FileInputStream from an InputStream. what i suggest is this: get the input stream from resource, then create a temp file,get a FileOutputStream from it. read the InputStream and copy it to FileOutputStream.
now the temp file has the contents of your resource file, and now you can create a FileInputStream from this file.
I don't know if this particular solution is useful to you, but i think it can be used in other situations.
As an example, if your file is in the assets folder, you get an InputStream and then a FileInputStream using this method:
InputStream is=getAssets().open("video.3gp");
File tempfile=File.createTempFile("tempfile",".3gp",getDir("filez",0));
FileOutputStream os=newFileOutputStream(tempfile);
byte[] buffer=newbyte[16000];
int length=0;
while((length=is.read(buffer))!=-1){
os.write(buffer,0,length);
}
FileInputStream fis=new FileInputStream(tempfile);

Method to read XML file and parse it

How to read an XML file saved in the local folder and then use the stream object to parse it?
You can use a FileInputStream (see docs).
File file = new File("C:\\Temp\\myxml.xml");
InputStream stream = new FileInputStream(file)
If you need an URL, you can use file.toURI().toURL() or use a File-URL: file://C:/Temp/myxml.xml
Otherwise, directly go with the FileInputStream as suggest by Jeff.

How to pass an InputStream via RMI

Consider these two functions:
Function A takes inputStream as parameter.
public void processStream(InputStream stream)
{
//Do process routine
}
Function B loads a file content to pass it to Function A as InputStream.
pulic void loadFile()
{
File file =new File("c:\\file.txt");
//Pass file as InputStream
}
How can I pass file from Function B to Function A as InputStream without reading it on first hand?
I did something like this:
File file = new File("c:\\file.txt");
DataInputStream stream= new DataInputStream(new FileInputStream(file));
This generated the exception below:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.io.DataInputStream
EDIT:
loadFile() is passing the InputStream as RMI response.
The following should work just fine
processStream(new FileInputStream(file));
You should only not attempt to serialize an InputStream instance by ObjectOutputStream like as
objectOutputStream.writeObject(inputStream);
which you're apparently doing in processStream() method. That's namely exactly what the exception is trying to tell you. How to solve it properly depends on the sole functional requirement which you omitted from the question.
Update as per the comment
I am passing the InputStream as an RMI response.
There's the problem. You cannot pass non-serializable objects around as RMI response, let alone unread streams. You need to read the InputStream into a ByteArrayOutputStream the usual IO way and then use its toByteArray() to get a byte[] out of it and pass that instead. Something like:
InputStream input = new FileInputStream(file);
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
byte[] bytes = output.toByteArray(); // Pass that instead to RMI response.
Be careful with large files though. Every byte of a byte[] eats one byte of JVM's memory.
That exception seems to indicate that you are calling the processStream method on a remote object using something like RMI? if that is the case, you will need to re-visit what you are doing. sending streams of data over RMI is not an easy thing to do. if you are guaranteed to be using small files, you could copy the file data to a byte[] and pass that to the remote method call. if you need to process larger files, however, that will most likely cause memory issues on the client and/or server. in that case, you should use something like rmiio, which provides utilities for streaming data over RMI.
You could just pass the FileInputStream ?
processStream(new FileInputStream(yourFile));
The reason you are getting the exception is because DataInputStream is intended to read primitive Java types

Categories