FileInputStream.read() vs FileOutputStream.write() - java

I tried to make a simple program that copies a file. According to the documentation, FileInputStream.read() and FileOuputStream.write() seemed similar to me. They read and write an int, from and to a file, respectively. So then, why does the following not work?
import java.io.*;
class CopyFile {
public static void main(String[] args) throws IOException {
FileInputStream original = new FileInputStream(args[0]);
FileOutputStream copy = new FileOutputStream(args[1]);
while (original.read() != -1) {
copy.write(original.read());
}
}
}
The resulting file is totally different from the original. Why isn't this working as I expected?

Look at your code:
while (original.read() != -1) {
copy.write(original.read());
}
You read one byte to test if it's end of file, then you read another byte to write.
Hence the byte you read in while condition is skipped.
The correct way is:
int b;
while ((b=original.read()) != -1) {
copy.write(b);
}

Related

Is there an -1 at the end of an Inputstream?

I am quite new to programming.
While reading the article Byte Streams in "Basic I/O" in The Java Tutorials by Oracle, I came accross this code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("xanadu.txt");
out = new FileOutputStream("outagain.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
I do not understand the condition of the while-loop. Is -1 some kind of sign that the Message is over? Does the FileOutputStream add it at the end?
Thank you all for your attention. I hope you have a wonderfull sylvester.
To add to the other answers, the tool for figuring this out is the documentation.
For the 'read' method of FileInputStream:
public int read()
throws IOException
Reads a byte of data from this input stream. This method blocks if no input is yet available. Specified by:
read in class InputStream
Returns: the next byte of data, or -1 if the
end of the file is reached.
This is definitive.
All standard Java classes are documented in this manner. In case of uncertainty, a quick check will reassure you.
EDIT: "Signals that an end of file or end of stream has been reached unexpectedly during input.
This exception is mainly used by data input streams, which generally expect a binary file in a specific format, and for which an end of stream is an unusual condition. Most other input streams return a special value on end of stream."
The right way is to catch EOFException to find out is it end of file or not, but in tihs case reading chars as EOF -1 is returned and not null, and it's working because there is no char for negative ascii, it's the same to check while ((c = in.read()) >= 0) {}, so you can use != -1 and it will work.

Read a file with InputStream

So I have a file that has one line of int : 5551212
I am trying to use InputStream to read this file and then see if I can extract the number written within in it
I did the following steps:
import java.io.*;
class Shuffle {
public static void main(String args[]) throws IOException {
FileInputStream newfile = new FileInputStream("file path");
System.out.println(newfile.getChannel());
System.out.println(newfile.getFD());
System.out.println("Number of remaining bytes:"+newfile.available());
int data;
while ((data = newfile.read()) != -1) {
System.out.print(data + " ");
}
newfile.close();
}
}
However, the output that I got is: 53, 53, 53, 49, 50, 49, 50
I am not really sure what this is suppose to represent, or simply how do I use InputStream on integers
With Java 11 or above, a file can be read using a single line of code - Files.readString
Here is a working example for reading a text file:
// File name: ReadFile.java
import java.nio.file.*;
public class ReadFile {
public static void main(String[] args) throws Exception {
String path = "my-file.txt";
// Read file content as a string
System.out.println(Files.readString(Paths.get(path)));
}
}
Output:
> javac ReadFile.java
> java ReadFile
5551212
The file you're reading is a text file, and thus the bytes you're receiving are representing encoded chars. If you look at ascii table (eg http://www.asciitable.com/) at decimal value 53, you'll see it's corresponding to a char "5"
You are reading an int, and the file is text data, not binary. Hence whatever bytes are in the file are interpreted as binary, and you get these numbers.
To read from a text file, you can either use a Scanner, or read as text first and then convert to int.
import java.io.*;
class Shuffle {
public static void main(String args[]) throws IOException {
try (InputStream file = new FileInputStream("file.txt");
InputStreamReader in = new InputStreamReader(file);
BufferedReader r = new BufferedReader(in)) {
String line = r.readLine();
while (line != null) {
int number = Integer.parseInt(line);
System.out.println(number);
line = r.readLine();
}
}
}
}
This code also uses try-with-resources, which makes sure all readers and files are closed at the end, even if an exception is thrown.

Reading binary data in Java

So for a project I am working on, I need to be reading binary data from .FRX files into my Java project. Java's standard byte reader however, keeps returning the wrong bytes for me, which I believe could be a result of Java's modified UTF8-encoding. If I use C#'s binary reading methods, I get the output that I require. An obvious (but proving to be difficult) solution is using C# and a DLL to wrap into the Java project, and I was just wondering if anyone has any simpler alternatives in Java, perhaps an alternative standard byte-reader which can be implemented in Java relatively easily.
Any help is greatly appreciated!
Question update
Here is my C# program, which returns the output I am looking for.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
public class GetFromFRX
{
public string getFromFRX(string filename, int pos)
{
StringBuilder buffer = new StringBuilder();
using (BinaryReader b = new BinaryReader(File.Open("frmResidency.frx", FileMode.Open)))
{
try
{
b.BaseStream.Seek(pos, SeekOrigin.Begin);
int length = b.ReadInt32();
for (int i = 0; i < length; i++)
{
buffer.Append(b.ReadChar());
}
}
catch (Exception e)
{
return "Error obtaining resource\n" + e.Message;
}
}
return buffer.ToString();
}
}
And here is some slightly differently formatted Java code:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
public class JavaReader {
public static void main(String[] args) throws Exception {
InputStream i = null;
BufferedInputStream b = null;
try{
// open file
i = new FileInputStream("frmResidency.frx");
// input stream => buffed input stream
b = new BufferedInputStream(i);
int numByte = b.available();
byte[] buf = new byte[numByte];
b.read(buf, 2, 3);
for (byte d : buf) {
System.out.println((char)d+":" + d);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(i!=null)
i.close();
if(b!=null)
b.close();
}
}
}
In your Java code:
You are using available() in a way which is specifically warned against in the Javadoc.
You aren't checking the result returned by the read() method.
You are reading into the buffer at offset 2 and then checking the entire buffer.
You are reading bytes where your C# code reads characters.
You aren't reading the length word.
You aren't using methods like DataInputStream.readInt() which correspond to your C# code.

BufferOutputStream write zero byte when merge the file

I am trying merge n pieces of file become single file. But I got strange behavior on my function. The function are called for x times in n seconds. Let say I have 100 files which I will merge, every second I call 5 files and merger it. and in the next second the amount is double to be 10, but from 1-5 is the same file as before the rest is new file. It work normal but in some point, its give zero byte or sometime give the right size.
Could you help me spot the mistake in my function below?
public void mergeFile(list<String> fileList, int x) {
int count = 0;
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream("Test.doc"));
for (String file : fileList) {
InputStream in = new BufferedInputStream(new FileInputStream(file));
byte[] buff = new byte[1024];
in.read(buff);
out.write(buff);
in.close();
count++;
if (count == x) {
break;
}
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
*sorry for my English
in.read(buff);
Check the Javadoc. That method isn't guaranteed to fill the buffer. It returns a value which tells you how many bytes it read. You're supposed to use that, and in this situation you are supposed to use it when deciding how many bytes, if any, to write.
You do not read the full file, you read from each file only up to 1024 bytes. You need to loop the read as long as it returns data (or use something like Files.copy().
BTW: you dont need a BufferedOutputStream if you copy with large buffers.
public void mergeFile(list<String> fileList, int x) throws IOException {
try (OutputStream out = new FileOutputStream("Test.doc");) {
int count=0;
for (String file : fileList) {
Files.copy(new File(file).toPath(), out);
count++;
if (count == x) {
break;
}
}
}
}
You also do not need to flush() if you close. I am using "try-with-resource" here, so I dont need to close it explicitely. It is best to propagate the exceptions.

In java is there a readObject() alternative for RandomAccessFile

I'm trying to save a couple of Strings but I'm currently using ObjectInputStream, which apparently doesn't save my data in a permanent manner. Here is the code which I commented in my project. It saves the string in a temporal manner. Anytime I exit my program, puff the data is gone:
ObjectInputStream FileIn= new ObjectInputStream(new FileInputStream("cars.txt"));
//AND HERE IS THE CODE FOR THE RandomAccessFile VERSION:
RandomAccessFile FileIn = new RandomAccessFile("cars.txt", "rw");
au=(Cars)FileIn.readObject(); //THIS readObject(), is giving me errors
//Cars is a Class
Is there any other alternative that I can use to read RandomAccessFile... Please help and thanks.
Just like FileInputStream, you need to wrap a RandomAccessFile in an ObjectInputStream. i.e. RandomAccessFile doesn't buy you anything.
final RandomAccessFile raf = new RandomAccessFile("file.dat", "r");
ObjectInputStream ois = new ObjectInputStream(new InputStream() {
#Override
public int read(byte[] b, int off, int len) throws IOException {
return raf.read(b, off, len);
}
#Override
public int read() throws IOException {
return raf.read();
}
});
For simple String objects is far easier using plain DataInputStream / DataOutputStream:
package test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
public class TestFile {
static final String FILE = "/tmp/cars.txt";
public static void main(String[] args) {
try {
List<String> strs = new ArrayList<String>();
strs.add("Audi");
strs.add("Seat");
strs.add("Renault");
saveStrings(strs);
strs = loadStrings();
System.out.println("Read strings: " + strs);
} catch (Exception e) {
}
}
static List<String> loadStrings() throws Exception {
DataInputStream dis = null;
List<String> list = new ArrayList<String>();
try {
dis = new DataInputStream(new FileInputStream(FILE));
while (dis.available() > 0) {
list.add(dis.readUTF());
}
} finally {
if (dis != null)
dis.close();
}
return list;
}
static void saveStrings(List<String> list) throws Exception {
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream(FILE));
for (String str : list) {
dos.writeUTF(str);
}
} finally {
if (dos != null)
dos.close();
}
}
}
If you are asking whether you can use RandomAccessFile to seek around inside an object stream and read objects then the short answer is "no". Serialized object streams are heavily encoded with backwards pointers to previously used objects including previously dumped class definitions, etc..
Serialization stream specification with some format details.
Here's some more details on the serialization format.
Discussion about random writing from Java docs.
We had a similar requirement and wrote some code which closes and re-opens the serialized stream once and a while and recorded the positions of these break points. This didn't give us the ability to read a particular object but it did give us the ability to append to serialized stream and to skip over a particular portion of the file -- skip to the next break.
Well you have to invoke, writeObject() instead of readObject() which is actually to read from disk to memory, and of course when the program ends, so does the memory used by that program.

Categories