I wanted to know about the difference between these two block of lines of codes.
byte[] fileBytes = FileUtils.readFileToByteArray(new File(completeFilePath.toString()));
..
return new FileTransfer(errorFileName, "application/vnd.ms-excel", is);
and
File csvFile = new File(completeFilePath.toString());
InputStream is = new BufferedInputStream(new FileInputStream(csvFile));
return new FileTransfer(errorFileName, "application/vnd.ms-excel", is);
any advantage and disadvantage for either of them is welcome to clear out detail.
Thanks in Advance.
FileTransfer has multiple constructors which expect different parameters.
Your first example calls the constructor which takes the content as a byte array (byte[]).
Your second example calls the constructor which takes an InputStream and will read the content itself from the passed InputStream.
If your file is big, obviously don't use the first one because it requires the whole file to be read into the memory.
The second approach seems better in all cases except if you also need the file content, then you would have to read it twice.
Related
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.
Consider the following code snippet getInputStreamForRead() method creates and returns a new input stream for read.
InputStream is = getInputStreamForRead(); //This method creates and returns an input stream for file read
is = getDecompressedStream(is);
Since the orginal file content is compressed and stored it has to be decompressed while reading. Hence getDecompressedStream() method below would provide option to decompress the stream content
public InputStream getDecompressedStream(InputStream is) throws Exception {
return new GZIPInputStream(is);
}
Have the following doubts
Which one is correct for the above snippet
is = getDecompressedStream(is)
or
InputStream newStream = getDecompressedStream(is)
Will reusing the InputStream variable again cause any trouble?
I'm completely new with streams. Kindly help me to know about this.
As long as:
you're not manipulating the original InputStream between the original assignment and the new invocation
you're always closing your streams in a finally statement
... you should be fine re-assigning to the original variable - it's just a new value passed to an existing reference.
In fact, that may be the recommended way, since you get to only close one Closeable programmatically, as GZIPInputStream#close...
Closes this input stream and releases any system resources associated with the stream.
(see here - I read this as, "closes the underlying stream").
Since you want to close the input stream correctly, the best way is to create the input stream using chaining, and using a try-with-resources to handle the close for you.
try (InputStream is = getDecompressedStream(getInputStreamForRead())) {
// code using stream here
}
I was trying to read from file and then write to other file. I use code bellow to do so.
byte[] bytes = Files.readAllBytes(file1);
Writer Writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file2), "UTF-8"));
for(int i=0;i<bytes.length;i++)
Writer.write(bytes[i]);
Writer.close();
But when I change file1 to picture.png and file2 to picture2.png, this method doesn't work and I can't open picture2.png using image viewer.
What have I done wrong?
Writers are for writing text, possibly in different formats (ie utf-8 / 16, etc). For writing raw bytes, don't use writers. Just use (File)OutputStreams.
It is truly as simple as
byte[] bytes = ...;
FileOutputStream fos = ...;
fos.write(bytes);
The other answers explain why what you have potentially fails.
I'm curious why you're already using one Java NIO method, but not others? The library already has methods to do this for you.
byte[] bytes = Files.readAllBytes(file1);
Files.write(file2, bytes, StandardOpenOption.CREATE_NEW); // or relevant OpenOptions
or
FileOutputStream out = new FileOutputStream(file2); // or buffered
Files.copy(file1, out);
out.close();
or
Files.copy(file1, file2, options);
The problem is that Writer.write() doesn't take a byte. It takes a char, which is variable size, and often bigger than one byte.
But once you've got the whole thing read in as a byte[], you can just use Files.write() to send the whole array to a file in much the same way that you read it in:
Files.write(filename, bytes);
This is the more modern NIO idiom, rather than using an OutputStream.
It's worth reading the tutorial.
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
I was handed some data in a file with an .dat extension. I need to read this data in a java program and build the data into some objects we defined. I tried the following, but it did not work
FileInputStream fstream = new FileInputStream("news.dat");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
Could someone tell me how to do this in java?
What kind of file is it? Is it a binary file which contains serialized Java objects? If so, then you rather need ObjectInputStream instead of DataInputStream to read it.
FileInputStream fis = new FileInputStream("news.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
// ...
(don't forget to properly handle resources using close() in finally, but that's beyond the scope of this question)
See also:
Basic serialization tutorial
A .dat file is usually a binary file, without any specific associated format. You can read the raw bytes of the file in a manner similar to what you posted - but you will need to interpret these bytes according to the underlying format. In particular, when you say "open" the file, what exactly do you want to happen in Java? What kind of objects do you want to be created? How should the stream of bytes map to these objects?
Once you know this, you can either write this layer yourself or use an existing API (assuming it's a standard format).
For reference, your example doesn't work because it assumes that the binary format is a character representation in the platform's default charset (as per the InputStreamReader constructor). And as you say it's binary, this will fail to convert the binary to a stream of characters (since, after all, it's not).
// BufferedInputStream not strictly needed, but much more efficient than reading
// one byte at a time
BufferedInputStream in = new BufferedInputStream (new FileInputStream("news.dat"));
This will give you a buffered stream which will return the raw bytes of the file; you can now either read and process them yourself, or pass this input stream to some library API that will create appropriate objects for you (if such a library exists).
That entirely depends on what sort of file the .dat is. Unfortunately, .dat is often used as a generic extension for a data file. It could be binary, in which case you could use FileInputStream fstream = new FileInputStream(new File("news.dat")); and call read() to get bytes from the file, or text, in which case you could use BufferedReader buff = new BufferedInputReader(new FileInputStream(new File("news.dat"))); and call readLine() to get each line of text. [edit]Or it could be Java objects in which case what BalusC said.[/edit]
In both cases, you'd then need to know what format the file was in to divide things up and get meaning from it, although this would be much easier if it was text as it could be done by inspection.
Please try the below code:
FileReader file = new FileReader(new File("File.dat"));
BufferedReader br = new BufferedReader(file);
String temp = br.readLine();
while (temp != null) {
temp = br.readLine();
System.out.println(temp);
}
A better way would be to use try-with-resources so that you would not have to worry about closing the resources.
Here is the code.
FileInputStream fis = new FileInputStream("news.dat");
try(ObjectInputStream objectstream = new ObjectInputStream(fis)){
objectstream.readObject();
}
catch(IOException e){
//
}