How FileInputStream read work? - java

Someone please explain me how buffer array is filled in the following code:
try {
byte[] buffer = new byte[1024];
//(1) this print an empty string?
System.out.println("1: " + new String(buffer));
FileInputStream inputStream = new FileInputStream("test.txt");
int len;
while((len = inputStream.read(buffer)) != -1) {
//(2) this print text on my file?
System.out.println("2: " + new String(buffer));
}
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Update: i have got useful info after reading following:
https://docs.oracle.com/javase/tutorial/essential/io/bytestreams.html
Buffered input streams read data from a memory area known as a buffer; the native input API is called only when the buffer is empty. Similarly, buffered output streams write data to a buffer, and the native output API is called only when the buffer is full
Thanks all!

The InputStream#read method will read data from the input stream into the supplied buffer.
See the java doc for details.
(In particular, see the return value – it will return -1 if there is no more data to read.)

Related

How is the write(byte[],int,int) method working?

public class JavaCopyFileProgram {
public static void main(String[] args)
{
File sourceFile = new File("F:/Study/Java/Java Programs/Factory Methods.txt");
File destFile = new File("D:/DestFile.txt");
FileInputStream inStream = null;
FileOutputStream outStream = null;
try
{
inStream = new FileInputStream(sourceFile);
outStream = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
int length;
while ((length = inStream.read(buffer)) != -1)
{
outStream.write(buffer, 0, length);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
inStream.close();
outStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
System.out.println("Success");
}
}
I am not able to understand how is thw write() method working? When it is first invoked then it is writing the cotents from 0 index to length of the byte array but when it is invoked second time then how is it appending the new text to the end of the previous text? It should override the previous content as again write is called with 0 as starting index. Please help me if i am understood something wrong?
The start offset in the write method does not refer to the offset in the FileOutputStream but to the offset in the array from which you write.
You can read in the documentation of OutputStream (rather than FileOutputStream) how the write method is supposed to be used.
For your specific write method call
outStream.write(buffer, 0, length);
it means: "write out the contents of buffer to stream outStream starting at buffer[0] the next length bytes".
The second and third parameter refer to the bounds of the array. The method will write buffer[0] to buffer[length - 1]. And since you read from inStream again and again (see head of the while loop), the contents of buffer will be filled with consecutive bytes from this input stream. The resulting operation is a file copy here.
The simplest form of the write() method is write( byte[] buffer ); it writes the entire buffer into the output stream.
However, it is often the case that we do not want to write an entire buffer, but only a portion of it. That's why the write( byte[] buffer, int offset, int length ) exists.
The code that you provided uses this variant of the write() method because the buffer is not always full, since read() call does not always read an entire buffer, it reads a length number of bytes.
In the code that you posted, the read() method is invoked each time with an offset of 0, which means that it reads bytes from the input stream and stores them into the buffer starting at offset 0. Therefore the write() method needs to also start fetching bytes to write into the output stream starting at offset zero of the buffer. That's why the offset to write is given as zero.
However, if you had a buffer containing 100 bytes, and you only wanted to write the middle 80, then you would have said write( buffer, 10, 80 ).

Is it possible to read images without ImageIO?

I am trying to read an image and deliver it through a Java socket. But there are some bits that does not fit. When viewing in a diff tool I realized that all numbers bigger than 127 were truncated.
So I wanted to just convert it to a char[] array and return it instead. Now I'm getting a complette different image, perhaps due to char's size.
try (PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename), BUFSIZ)) {
byte[] buffer = new byte[BUFSIZ];
while (in.read(buffer) != -1) {
response.append(new String(buffer));
out.print(response.toString());
response.setLength(0);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
This is my reading and delivering code.
I've read many times to use ImageIO but I want to do it without, since I don't know whether it's an image or not. (And what about other file types like executables?)
So, is there any way to convert it to something like an unsigned byte that'll be delivered correctly on the client? Do I have to use something different than read() to achieve that?
Writers are for character data. Use the OutputStream. And you're making the usual mistake of assuming that read() filled the buffer.
The following loop will copy anything correctly. Memorize it.
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Repeat after me: a char is not a byte and it's not a code point.
Repeat after me: a Writer is not an OutputStream.
try (OutputStream out = this.socket.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename), BUFSIZ)) {
byte[] buffer = new byte[BUFSIZ];
int len;
while ((len = in.read(buffer))) != -1) {
out.write(buffer, 0, len);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
(this is from memory, check the args for write()).

corrupted file text while reading

I have the following code:
BlobDomain blobDomain = null;
OutputStream out = null;
try {
blobDomain = new BlobDomain();
out = blobDomain.getBinaryOutputStream();
byte[] buffer = new byte[8192];
int bytesRead = 0;
while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
out.write(buffer, 0, bytesRead);
String line = (new String(buffer));
fullText += line;
}
} catch (Exception e) {
//do nothing
}finally{
if (out != null)
try {
out.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
when i print the fullText what i see for larger files is that end part of the text is added again to the fullText. So full text has some lines repeated in the end. any suggestions on what is wrong here?
The reason that you are getting this is that you are writing the entire buffer every time to your String. Thus, when you reach the end of the file you may not have read exactly the amount of bytes that your buffer is sized at. The old data is still in the buffer and will also be written to your String.
One option to solve this may be to write your data to a String first and then to write your String to the output stream. This should also be faster than adding to a String after each read.
Save inputStream to String:
java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\\A");
fullText = s.hasNext() ? s.next() : "";
Write String to output stream:
out.write(fullText.getBytes());
If you want to keep you code as-is then perform a substring on the buffer and retrieve only the amount of bytes read. For example:
String line = (new String(buffer.substring(0,bytesRead));

How to write RAW data to a file using Java? e.g same as: nc -l 8000 > capture.raw

In TCP i am receiving media stream from an IP camera as RAW. According to there advise, i need to write that as file. And then i can play it with media player such as VLC.
But when i write this to a file, and play with media players it never play corrupted.
After comparing the original file i see my Java writing it in wrong characters. And there sample file shows different. What or how do i fix such file writing issue, here is how i am writing it:
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
bytes_read = sock.getInputStream().read(buf, 0, buf.length);
String data = new String(buf, 0, bytes_read);
System.err.println("DATA: " + bytes_read + " bytes, data=" +data);
BufferedWriter out = new BufferedWriter(
new FileWriter("capture.ogg", true));
out.write(data);
out.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
You shouldn't use Readers, Writers and Strings for binary data. Stick with InputStreams and OutputStreams.
I.e., change
BufferedWriter -> BufferedOutputStream,
FileWriter -> FileOutputStream
and instead of String, just use a byte[].
If you're dealing with sockets, I must advice you to look into the NIO package though.
You're doing it right... at least until the part where you turn your byte[] into a String:
That step only really makes sense if your byte[] represents textual data in the first place! Which it doesn't!
Whenever you handle binary data or don't actually care what the data represents you must avoid using String/Reader/Writer to handle that data. Instead do use byte[]/InputStream/OutputStream.
Also, you must read from the socket in a loop, because nothing guarantees that you've read everything:
byte[] buf=new byte[1024];
int bytes_read;
OutputStream out = new FileOutputStream("capture.ogg", true);
InputStream in = sock.getInputStream();
while ((bytes_read = in.read(buf)) != -1) {
out.write(buf, 0, bytes_read);
}
out.close();
The way you have it written limits the output file to a maximum size of 1024 bytes. Try a loop:
try {
byte[] buf = new byte[1024];
int bytes_read = 0;
InputStream in = sock.getInputStream();
FileOutputStream out = new FileOutputStream(new File("capture.ogg"));
do {
bytes_read = in.read(buf, 0, buf.length);
System.out.println("Just Read: " + bytes_read + " bytes");
if (bytes_read < 0) {
/* Handle EOF however you want */
}
if (bytes_read > 0)
out.write(buf, 0, bytes_read);
} while (bytes_read >= 0);
out.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}

Java: Outputting text file to Console

I'm attempting to output a text file to the console with Java. I was wondering what is the most efficient way of doing so?
I've researched several methods however, it's difficult to discern which is the least performance impacted solution.
Outputting a text file to the console would involve reading in each line in the file, then writing it to the console.
Is it better to use:
Buffered Reader with a FileReader, reading in lines and doing a bunch of system.out.println calls?
BufferedReader in = new BufferedReader(new FileReader("C:\\logs\\"));
while (in.readLine() != null) {
System.out.println(blah blah blah);
}
in.close();
Scanner reading each line in the file and doing system.print calls?
while (scanner.hasNextLine()) {
System.out.println(blah blah blah);
}
Thanks.
If all you want to do is print the contents of a file (and don't want to print the next int/double/etc.) to the console then a BufferedReader is fine.
Your code as it is won't produce the result you're after, though. Try this instead:
BufferedReader in = new BufferedReader(new FileReader("C:\\logs\\log001.txt"));
String line = in.readLine();
while(line != null)
{
System.out.println(line);
line = in.readLine();
}
in.close();
I wouldn't get too hung up about it, though because it's more likely that the main bottleneck will be the ability of your console to print the information that Java is sending it.
If you're not interested in the character based data the text file is containing, just stream it "raw" as bytes.
InputStream input = new BufferedInputStream(new FileInputStream("C:/logs.txt"));
byte[] buffer = new byte[8192];
try {
for (int length = 0; (length = input.read(buffer)) != -1;) {
System.out.write(buffer, 0, length);
}
} finally {
input.close();
}
This saves the cost of unnecessarily massaging between bytes and characters and also scanning and splitting on newlines and appending them once again.
As to the performance, you may find this article interesting. According the article, a FileChannel with a 256K byte array which is read through a wrapped ByteBuffer and written directly from the byte array is the fastest way.
FileInputStream input = new FileInputStream("C:/logs.txt");
FileChannel channel = input.getChannel();
byte[] buffer = new byte[256 * 1024];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
try {
for (int length = 0; (length = channel.read(byteBuffer)) != -1;) {
System.out.write(buffer, 0, length);
byteBuffer.clear();
}
} finally {
input.close();
}
If it's a relatively small file, a one-line Java 7+ way to do this is:
System.out.println(new String(Files.readAllBytes(Paths.get("logs.txt"))));
See https://docs.oracle.com/javase/7/docs/api/java/nio/file/package-summary.html for more details.
Cheers!
If all you want is most efficiently dump the file contents to the console with no processing in-between, converting the data into characters and finding line breaks is unnecessary overhead. Instead, you can just read blocks of bytes from the file and write then straight out to System.out:
package toconsole;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) {
BufferedInputStream bis = null;
byte[] buffer = new byte[8192];
int bytesRead = 0;
try {
bis = new BufferedInputStream(new FileInputStream(args[0]));
while ((bytesRead = bis.read(buffer)) != -1) {
System.out.write(buffer, /* start */ 0, /* length */ bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try { bis.close(); } catch (Exception e) { /* meh */ }
}
}
}
In case you haven't come across this kind of idiom before, the statement in the while condition both assigns the result of bis.read to bytesRead and then compares it to -1. So we keep reading bytes into the buffer until we are told that we're at the end of the file. And we use bytesRead in System.out.write to make sure we write only the bytes we've just read, as we can't assume all files are a multiple of 8 kB long!
FileInputStream input = new FileInputStream("D:\\Java\\output.txt");
FileChannel channel = input.getChannel();
byte[] buffer = new byte[256 * 1024];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
try {
for (int length = 0; (length = channel.read(byteBuffer)) != -1;) {
System.out.write(buffer, 0, length);
byteBuffer.clear();
}
} finally {
input.close();
}
Path temp = Files.move
(Paths.get("D:\\\\Java\\\\output.txt"),
Paths.get("E:\\find\\output.txt"));
if(temp != null)
{
System.out.println("File renamed and moved successfully");
}
else
{
System.out.println("Failed to move the file");
}
}
For Java 11 you could use more convenient approach:
Files.copy(Path.of("file.txt"), System.out);
Or for more faster output:
var out = new BufferedOutputStream(System.out);
Files.copy(Path.of("file.txt"), out);
out.flush();

Categories

Resources