Yes because you are writing bytes
out.write(((byte)temp[j]))
you need to write int which is 4 bytes. Not truncate the int to byte
out.write(temp[j])
Eventually this is not the way to write the image - this will reproduce the file so its ok for this application (just copy a file nothing more). But if you want to change the pixels and rewrite a new image you will need imageio (or some other mechanism) to write images.
--
OutputStreamWriter writes characters; why dont you use the equivalent:
FileOutputStream: you can write the bytes as you read them.
Answer from gpasch on Stack Overflowpublic class DownloadImage {
public static void main(String[] args){
FileOutputStream out = null;
FileInputStream in = null;
int cursor;
try{
in = new FileInputStream(new File("C:\\Users\\ganesh.r\\Desktop\\My Stuff\\dp.jpeg"));
out = new FileOutputStream("TestImage.jpeg");
while((cursor = in.read())!=-1){
out.write(cursor);
}
}
finally{
if(in!=null){
in.close();
}
if(out!=null){
out.close();
}
System.out.println("Read and Write complete");
}
}
}
Hope this helps
try {
FileInputStream fin=new FileInputStream(new File("C:\\Folder1\\img.png"));
FileOutputStream fout=new FileOutputStream(new File("C:\\Folder1\\newimg.png"));
int content;
while ((content = fin.read()) != -1) {
fout.write(content);
}
System.out.println("Finished");
} catch (IOException e) {
e.printStackTrace();
}
The problem, as I can see it, is the mixing of the readers and streams..
Now, I tried using...
try (OutputStream output = new FileOutputStream(filepath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output))) {
writer.write("Number: 176");
writer.newLine();
writer.write("Title: Elephant");
writer.newLine();
writer.write("Text: This image shows a cute elephant.");
writer.newLine();
writer.flush();
ImageIO.write(image, "png", output);
output.flush();
} catch (Exception exp) {
exp.printStackTrace();
}
To write the file. The hope was that the input stream position would be updated and the content would be written to the end of the file...
And
String filepath = "myfile.txt";
BufferedImage image = null;
try (InputStream is = new FileInputStream(new File(filepath));
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String number = br.readLine();
String title = br.readLine();
String text = br.readLine();
System.out.println(number);
System.out.println(title);
System.out.println(text);
ImageInputStream iis = ImageIO.createImageInputStream(is);
image = ImageIO.read(iis);
ImageIO.write(image, "png", new File("test.png"));
} catch (Exception exp) {
exp.printStackTrace();
}
To read it.
But this didn't seem to work. What "might" be happening is the file position isn't being updated to the correct position that we need it to read the image properly.
What I did instead was this...
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
public class ReadWriteImage {
public static void main(String[] args) {
try {
writeTest();
readTest();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void readTest() throws IOException {
String filepath = "myfile.txt";
BufferedImage image = null;
try (InputStream is = new FileInputStream(new File(filepath))) {
int lineCount = 0;
StringBuilder sb = new StringBuilder(128);
String number = null;
String title = null;
String text = null;
int b = -1;
while (lineCount < 3 && (b = is.read()) != -1) {
if ((char)b == '\n') {
switch (lineCount) {
case 0:
number = sb.toString();
break;
case 1:
title = sb.toString();
break;
case 2:
text = sb.toString();
break;
}
sb.delete(0, sb.length());
lineCount++;
} else {
sb.append((char)b);
}
}
System.out.println(number);
System.out.println(title);
System.out.println(text);
ImageInputStream iis = ImageIO.createImageInputStream(is);
image = ImageIO.read(iis);
ImageIO.write(image, "png", new File("test.png"));
} catch (Exception exp) {
exp.printStackTrace();
}
}
public static void writeTest() throws IOException {
String filepath = "myfile.txt";
BufferedImage image = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/thumnails/2005-09-29-3957_400.jpg"));
try (FileOutputStream output = new FileOutputStream(filepath)) {
output.write("Number: 176\n".getBytes());
output.write("Title: Elephant\n".getBytes());
output.write("Text: This image shows a cute elephant.\n".getBytes());
ImageIO.write(image, "png", output);
output.flush();
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
Basically, I just used the OutputStream and InputStream directly...
Updated
The file contents starts with...
Number: 176
Title: Elephant
Text: This image shows a cute elephant.
âPNG
Welcome to 2021
So, the ordinal answer was made some time ago, the world has moved on. Unless you have a very specific need not to (ie transport speed/bandwidth restrictions), I would highly recommend making use of things like JSON and Base64 to send binary and text mixed together.
The main reason, it's actually much simpler to encode/decode and maintain. The original solution is rather difficult to add new content to, as both ends need to be able to support the changes, where as something like JSON can (if done properly) get away with adding and removing content. It's also easier to build much more complex parsing workflows, as you're not reliant on the "read/write" position of the stream.
This example makes use of the org.json library, but you can use what ever library you want.
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import org.json.JSONObject;
public class Main {
public static void main(String[] args) throws IOException {
new Main();
}
public Main() throws IOException {
read(write());
}
public String write() throws IOException {
BufferedImage image = ImageIO.read(getClass().getResource("/images/Background.png"));
JSONObject jobj = new JSONObject();
jobj.put("number", 176);
jobj.put("title", "Elephant");
jobj.put("text", "This image shows a cute elepant");
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(image, "png", baos);
baos.flush();
byte[] encode = Base64.getEncoder().encode(baos.toByteArray());
String text = new String(encode, StandardCharsets.UTF_8);
jobj.put("image", text);
}
String text = jobj.toString();
return text;
}
public void read(String jsonText) throws IOException {
JSONObject jobj = new JSONObject(jsonText);
System.out.println("Number = " + jobj.getInt("number"));
System.out.println("Title = " + jobj.getString("title"));
System.out.println("Text = " + jobj.getString("text"));
String encodedImage = jobj.getString("image");
byte[] imageBytes = Base64.getDecoder().decode(encodedImage.getBytes(StandardCharsets.UTF_8));
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes)) {
BufferedImage image = ImageIO.read(bais);
JLabel label = new JLabel(new ImageIcon(image));
label.setText("<html>Number = " + jobj.getInt("number") + "<br>Title = " + jobj.getString("title") + "<br>Text = " + jobj.getString("text"));
JOptionPane.showMessageDialog(null, label);
}
}
}
What if I want to send 2 files?
Then use a JSONArray. org.json is reasonably powerful, see Introduction to JSON-Java for more details. The Google implementation (GSON?) also provides a lot of functionality which can be used to encode/decode json from/to POJOs, if that's your thing
Approach given your example:
This simple, if you only have 3 lines of text as listed in your example, then you can just read each line of Text when you detect the \n, when you get to the third one you know the image data is next and then just read from that offset into your image.
A better way to do it is to write a simple index header first with the offset of the binary data and then you don't have to do the parsing of the \n you can just read up to the offset and treat all that as text and then read from the offset on and treat the rest as your image.
There is no reason you need to encode anything to Base64 or anything like that, that will just bloat your file format and cause more complication than good.
XXXInputStream and XXXOutputStream (where XXX varies, there's a lot of options) deal with 8-bit bytes. For example, OutputStream.write(byte[] c);
XXXWriter or XXXReader deal with 16-bit chars. For example, Reader.read(char[] cbuf).
OutputStreamWriter converts an OutputStream to a Writer. As you may have guessed, InputStreamReader converts from an InputStream to a Reader. I am unaware of any classes that do the reverse, i.e. convert a Reader to an InputStream.
FileWriter is a Writer that talks to files. Since a Java String internally uses chars (16 bit so they can handle Unicode), FileWriter is the natural class for use with Unicode Strings.
FileOutputStream is an OutputStream for writing bytes to a file. OutputStreams do not accept chars (or Strings). By wrapping it in an OutputStreamWriter you now have a Writer, which does accept Strings.
Now, the real question, is when do you use a Reader/Writer and when a Stream? I've used Java for years and sometimes I get confused too. I believe the following to be correct:
Handy Guide - How to Decide Which to use:
- If you are dealing with binary data (e.g. an image) use Streams.
- If you are using non-ASCII Unicode characters, e.g. Chinese, use Readers/Writers.
- If you are using ordinary ASCII text (the traditional 0-127 characters) you can (usually) use either.
Some other links:
inputstream and reader in Java IO
InputStream vs InputStreamReader
There is actually no difference per se, FileWriter is just a convenience class. It extends OutputStreamWriter and creates the needed FileOutputStream itself.
Regarding write(int): that method writes a single character with the specified codepoint to the stream, it does not write a textual representation of the numeric value.
As for the empty file, note that you should always flush the buffer when you want the things you've written flushed to the underlying store (be it a file or a network stream or whatever you can think of). Simply call os.flush() after writing, that should do it.
EDIT: As Thilo has correctly mentioned, closing the stream should already flush it (and all underlying streams).
And last but not least, you should nearly always explicitly specify the charset/encoding you want your Writer to write in. Writers write characters, while OutputStreams write bytes, so you have to specify how those characters should be encoded into bytes. If you don't specify an encoding, the system default gets used, which may not be what you want.
Yes, your conclusion is correct subclasses of Reader and Writer are for reading/writing text content. InputStream / OutputStream are for binary content. If you take a look at the documentation:
Reader- Abstract class for reading character streams
InputStream- Abstract class is the superclass of all classes representing an input stream of bytes.
FileReader (and indeed anything extending Reader) is indeed for text. From the documentation of Reader:
Abstract class for reading character streams.
(Emphasis mine.) Look at the API and you'll see it's all to do with text - char instead of byte all over the place.
InputStream and OutputStream are for binary data, such as mp4 files.
Personally I would avoid FileReader altogether though, as it always uses the system default character encoding - at least before Java 11. Instead, use InputStreamReader around a FileInputStream... but only when you want to deal with text. (Alternatively, use Files.newBufferedReader.)
As an aside, that's a very inefficient way of copying from an input to an output... use the overloads of read and write which read into or write from a buffer - either a byte[] or a char[]. Otherwise you're calling read and write for every single byte/character in the file.
You should also close IO streams in finally blocks so they're closed even if an exception is thrown while you're processing them.
to help illustrate I create a project with a source directory
src
below source I had a package starthere with a class Main
I create another source directory xxx and put in a file a.txt
I also created under xxx a directory called text and put in a file named b.txt
Also I created under src a directory called other and put in a file called c.txt
My code is
URL url = Main.class.getResource("/a.txt");
System.out.println(url);
URL url2 = Main.class.getResource("/text/b.txt");
System.out.println(url2);
URL url3 = Main.class.getResource("/other/c.txt");
System.out.println(url3);
and my output is
D:\temp>java -cp ab.jar starthere.Main
jar:file:/D:/temp/ab.jar!/a.txt
jar:file:/D:/temp/ab.jar!/text/b.txt
jar:file:/D:/temp/ab.jar!/other/c.txt
edit
As you are not wanting to use a File, but simply the InputStream, you can use
InputStream fis = Main.class.getResourceAsStream("/a.txt");
and then set using ps.setBinaryStream(1, fis);
Consider following package structure
/
/testing_package
/testing_package/Main.java
/testing_package/Image.png
Now Here is a program to get Image.png and put it in database
public class Main {
public static void main(String...args) {
System.out.println(Main.class.getResource("image.jpg"));
//PreparedStatement as ps
ps.setBinaryStream(1, Main.class.getResourceAsStream("image.jpg")));
}
}
Thing to keep in mind
When using getResource(...) or getResourceAsStream(...) use relative location to the class instance whose function you are invoking.
Have a look at this answer too