Yes you are rather getting it wrong. But it easy to get it wrong ... if you don't understand the Java way of modeling textual data.
You are conflating the functionality of Reader / Writer with that of InputStream / OutputStream.
- The former allow you to consume (read) and produce (write) characters; i.e. textual data represented using Unicode code-points.
- The latter allow you to consume (read) and produce (write) bytes; i.e. binary or binary encoded data.
Now many Reader and Writer classes actually perform two functions at the same time; i.e. sourcing or sinking the data AND converting the data to / from characters. In some cases, you can tell the class how to do the conversion step by supplying an encoding.
By contrast an InputStream or OutputStream is a source or sink for bytes, and typically1 doesn't do any character translation.
In the case of Files.readAllBytes, the method is reading all of the bytes from a file and putting them into a byte array. It doesn't take a Charset parameter because it is not designed to do any decoding.
On the other hand, Files.readAllLines does take a Charset. That is because it is delivering the file content as an array of String objects representing the lines of the file. To when converting bytes to a Java String you need to say how the text / characters represented by the bytes are encoded.
1 - Hypothetically it could ... but you will see that Java doesn't provide classes like ReaderInputStream or WriterOutputStream. There is little need for them.
Yes you are rather getting it wrong. But it easy to get it wrong ... if you don't understand the Java way of modeling textual data.
You are conflating the functionality of Reader / Writer with that of InputStream / OutputStream.
- The former allow you to consume (read) and produce (write) characters; i.e. textual data represented using Unicode code-points.
- The latter allow you to consume (read) and produce (write) bytes; i.e. binary or binary encoded data.
Now many Reader and Writer classes actually perform two functions at the same time; i.e. sourcing or sinking the data AND converting the data to / from characters. In some cases, you can tell the class how to do the conversion step by supplying an encoding.
By contrast an InputStream or OutputStream is a source or sink for bytes, and typically1 doesn't do any character translation.
In the case of Files.readAllBytes, the method is reading all of the bytes from a file and putting them into a byte array. It doesn't take a Charset parameter because it is not designed to do any decoding.
On the other hand, Files.readAllLines does take a Charset. That is because it is delivering the file content as an array of String objects representing the lines of the file. To when converting bytes to a Java String you need to say how the text / characters represented by the bytes are encoded.
1 - Hypothetically it could ... but you will see that Java doesn't provide classes like ReaderInputStream or WriterOutputStream. There is little need for them.
No, you only need a Charset if you want represent the bytes as a String (i.e. as text) because the meaning of the bytes depends on the encoding.
byte[] bytes = Files.readAllBytes(Paths.get("/temp.txt"));
String text = new String(bytes, StandardCharsets.ISO_8859_1);
A single byte array can represent multiple different strings depending on the encoding and the bytes in the array are independent of the encoding, so it doesn't make sense to be able to pass the encoding as an argument to this function.
Since java 7 it is not needed to read byte by byte, there are two utility function in Files:
Path path = Paths.get("C:/temp/test.txt");
// Load as binary:
byte[] bytes = Files.readAllBytes(path);
String asText = new String(bytes, StandardCharset.ISO_8859_1);
// Load as text, with some Charset:
List<String> lines = Files.readAllLines(path, StandardCharsets.ISO_8859_1);
As you want to read binary data, one would use readAllBytes.
String and char is for text. As opposed to many other programming languages, this means Unicode, so all scripts of the world may be combined. char is 16 bit as opposed to the 8 bit byte.
For pure ASCII, the 7 bit subset of Unicode / UTF-8, byte and char values are identical.
Then you might have done the following (low-quality code):
int fileLength = (int) path.size();
char[] chars = new char[fileLength];
int i = 0;
int data;
while ((data = inputStream.read()) != -1) {
chars[i] = (char) data; // data actually being a byte
++i;
}
inputStream.close();
String text = new String(chars);
System.out.println(Arrays.toString(chars));
The problem you had, probably concerned the unwieldy fixed size array in java, and that a char[] still is not a String.
For binary usage, as you seem to be reading serialized data, you might like to dump the file:
int i = 0;
int data;
while ((data = inputStream.read()) != -1) {
char ch = 32 <= data && data < 127 ? (char) data : ' ';
System.out.println("[%06d] %02x %c%n", i, data, ch);
++i;
}
Dumping file position, hex value and char value.
it is simple example:
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();
}
}
}
}
If you want to read text(characters) - use Readers, if you want to read bytes - use Streams
Here's one way to solve this without relying on third-party libraries:
inputStream.reset();
byte[] bytes = new byte[inputStream.available()];
DataInputStream dataInputStream = new DataInputStream(inputStream);
dataInputStream.readFully(bytes);
Or if you don't mind using thirdparties (Commons IO):
byte[] bytes = IOUtils.toByteArray(is);
Guava also helps:
byte[] bytes = ByteStreams.toByteArray(inputStream);
You can use the good old read method like this:
public static byte[] readAllBytes(InputStream inputStream) throws IOException {
final int bufLen = 1024;
byte[] buf = new byte[bufLen];
int readLen;
IOException exception = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
outputStream.write(buf, 0, readLen);
return outputStream.toByteArray();
} catch (IOException e) {
exception = e;
throw e;
} finally {
if (exception == null) inputStream.close();
else try {
inputStream.close();
} catch (IOException e) {
exception.addSuppressed(e);
}
}
}