Java socket, get image file but it doesn't open - java

That's my first question so I hope I write it correctly.
I am trying to send an byte[] array through a Java socket, that array contains an image.
Here is the code to send the file:
public void WriteBytes(FileInputStream dis) throws IOException{
//bufferEscritura.writeInt(dis.available()); --- readInt() doesnt work correctly
Write(String.valueOf((int)dis.available()) + "\r\n");
byte[] buffer = new byte[1024];
int bytes = 0;
while((bytes = dis.read(buffer)) != -1){
Write(buffer, bytes);
}
System.out.println("Photo send!");
}
public void Write(byte[] buffer, int bytes) throws IOException {
bufferEscritura.write(buffer, 0, bytes);
}
public void Write(String contenido) throws IOException {
bufferEscritura.writeBytes(contenido);
}
My image:
URL url = this.getClass().getResource("fuegos_artificiales.png");
FileInputStream dis = new FileInputStream(url.getPath());
sockManager.WriteBytes(dis);
My code to get the image file:
public byte[] ReadBytes() throws IOException{
DataInputStream dis = new DataInputStream(mySocket.getInputStream());
int size = Integer.parseInt(Read());
System.out.println("Recived size: "+ size);
byte[] buffer = new byte[size];
System.out.println("We are going to read!");
dis.readFully(buffer);
System.out.println("Photo received!");
return buffer;
}
public String Leer() throws IOException {
return (bufferLectura.readLine());
}
And to create an image file:
byte[] array = tcpCliente.getSocket().LeerBytes();
FileOutputStream fos = new FileOutputStream("porfavor.png");
try {
fos.write(array);
}
finally {
fos.close();
}
The image file is created but when I try to open it for example with Paint it says that it can't open it because it is damaged...
I also tried to open both images (the original and the new one) with notepad and they have the same data inside!
I don't know what is happening...
I hope you help me.
Thanks!

Don't use available() as a measure of file length. It isn't. There is a specific warning in the Javadoc about that.
Use DataOutputStream.writeInt() to write the length, and DataInputStream.readInt() to read it, and use the same streams to read the image data. Don't use multiple streams on the same socket.
Also in this:
URL url = this.getClass().getResource("fuegos_artificiales.png");
FileInputStream dis = new FileInputStream(url.getPath());
the second line should be:
InputStream in = URL.openConnection.getInputStream();
A class resource is not a file.

Related

Adding buffer when writing byte[] to OutputStream [duplicate]

This question already has answers here:
Easy way to write contents of a Java InputStream to an OutputStream
(24 answers)
Closed 6 years ago.
In my method, I'm saving data from file to an output stream.
For now, it looks like this
public void readFileToOutputStream(Path path, OutputStream os) {
byte[] barr = Files.readAllBytes(path)
os.write(barr);
os.flush();
}
But in this solution, all bytes are loaded into memory, and I want to use buffer to release some of it.
What can I use to supply my reading with buffer?
easist way is to use Commons IO library
public void readFileToOutputStream(Path path, OutputStream os) throws IOException {
try(InputStream in = new FileInputStream(path.toFile())){
IOUtils.copy(in, os);
}
}
You can implement on your own similar to IOUtils.copy
public void readFileToOutputStream(Path path, OutputStream os) throws IOException {
try (InputStream fis = new FileInputStream(path.toFile());
InputStream bis = new BufferedInputStream(fis)) {
byte[] buffer = new byte[4096];
int n;
while ((n = bis.read(buffer)) >= 0) {
os.write(buffer, 0, n);
}
}
}
If i understand your question right, you would like to only write a specified amount of bytes to memory?
outputstreams write method can also write a specified byte array from a starting offset and length.
https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html
public void readFileToOutputStream(Path path, OutputStream os, int off, int len) {
byte[] barr = Files.readAllBytes(path)
os.write(barr, off, len);
os.flush();
}
Use buffered streams to manage the buffer for you:
public void readFileToOutputStream(Path path, OutputStream os) {
try (FileInputStream fis = new FileInputStream(path.toFile())) {
try (BufferedInputStream bis = new BufferedInputStream(fis)) {
try (DataInputStream dis = new DataInputStream(bis)) {
try (BufferedOutputStream bos = new BufferedOutputStream(os)) {
try (DataOutputStream dos = new DataOutputStream(bos)) {
try {
while (true) {
dos.writeByte(dis.readByte());
}
} catch (EOFException e) {
// normal behaviour
}
}
}
}
}
}
}
Use FileInputStream::read(byte[] b, int off, int len) link
to read up to len bytes to buffer b and FileOutputStream::write(byte[] b, int off, int len) link2 to write from buffer

compress and decompress String using DeflaterOutputStream and InflaterInputStream in java

I need to save a string on a file and I am using DeflaterOutputStream to compress. when I try to decompress I can't get the original String. I get an uncleared symbols.
Her is my code:
public static void decompress() throws Exception {
InputStream in=new FileInputStream("E:/codes.txt");
InflaterInputStream ini = new InflaterInputStream(in);
ByteArrayOutputStream bout =new ByteArrayOutputStream(512);
int b;
while ((b = in.read()) != -1) {
bout.write(b);
}
ini.close();
bout.close();
String s=new String(bout.toByteArray());
System.out.print(s);
}
public static void compressData(byte[] data) throws Exception {
OutputStream out=new FileOutputStream("E:/test.txt");
Deflater d = new Deflater();
DeflaterOutputStream dout = new DeflaterOutputStream(out, d);
dout.write(data);
dout.close();
}
public static void main(String[] args) throws Exception {
compressData("My name is Motasem".getBytes());
decompress();
}
I don't where exactly is the problem . I though it's in converting the byte array to String but I tried it and it is working. You can check this website http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/
You have a simple but hard to notice bug. You are not actually using your InflaterInputStream to read the data. You are just opening and closing it. Your code reading the file is:
while ((b = in.read()) != -1) {
Should be
while ((b = ini.read()) != -1) {

Google Appengine JAVA - Zip lots of images saving in Blobstore

I developed a simple media library where you can choose a set of images and download them.
When a client request a download, a servlet receives the blob keys to use for create a zip file and then a Task is launched for the procedure
The task iterate through the received blob keys and zip the images into the archive. When the task has finished a mail with the download link is sent to the user.
Here is my problem:
FileWriteChannel writeChannel = fileService.openWriteChannel(file, lock);
OutputStream blobOutputStream = Channels.newOutputStream(writeChannel);
ZipOutputStream zip = new ZipOutputStream(blobOutputStream);
A single channel can handle only this amount of bytes
BlobstoreService.MAX_BLOB_FETCH_SIZE
Because of that, i must open and close the channel every 1mb of data i have to write (same issue for the read, but for the read i used this code and it works). or the write() method throws a null exception
Opening and closing the channel with a normal outputStream, does not presents issue, like this code
But handling a Zip file i also have to manage
ZipOutputStream zip = new ZipOutputStream(blobOutputStream);
ZipEntry zipEntry = new ZipEntry(image_file_name);
zipOut.putNextEntry(zipEntry);
// while the image has bytes to write
zipOut.write(bytesToWrite);
After i wrote 1MB of data in the ZipEntry i have to close the channel and open it again.
So here the problem: where i open a new channel i can't access to the previouse zipEntry i was writing and then i cannot continue to write the next 1MB of the image i'm processing.
And, after a open a new channel, if i try to write on the zipEntry object (w/o re-initializing it) i get a ClosedChannel exception
Here is the SAMPLE code i wrote, i know is not working, but explains what i am trying to do.
My question then: How (if is possible, off course) can i create a zip file writing 1MB per time?
I'm also available to other approaches, the thing i need is to zip some images into one zip and save it into the blobstore, if you have other ideas to make this, please tell me
You should create you own stream that can manipulate channels. When the blob size limit is reached your stream closes current channel and opens a new one.
Example for local files:
public class ZipChannels {
public static void main(String[] args) throws IOException {
File dirToZip = new File("target\\dependency");
//create zip-files
ChannelOutput out = new ChannelOutput();
ZipOutputStream zip = new ZipOutputStream(out);
int b = 0;
for(File file: dirToZip.listFiles()) {
ZipEntry zipEntry = new ZipEntry(file.getName());
zip.putNextEntry(zipEntry);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
while((b = bis.read()) != -1) {
zip.write(b);
}
bis.close();
zip.closeEntry();
}
zip.close();
//merge all into one file for check it
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("package_all.zip"));
for (int i = 0; i < out.getChannelCount(); i++) {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("package_" + i + ".zip"));
while((b = bis.read()) != -1) {
bos.write(b);
}
bis.close();
}
bos.close();
}
public static class ChannelOutput extends OutputStream {
private OutputStream channel;
private int count = 0;
final private int MAX = 1000000;
#Override
public void write(int b) throws IOException {
if(count++ % MAX == 0) {
openNewChannel();
}
channel.write(b);
}
protected void openNewChannel() throws IOException {
if(channel != null) {
channel.close();
}
channel = new BufferedOutputStream(new FileOutputStream("package_" + (count / MAX) + ".zip"));
}
public int getChannelCount() {
return count / MAX + 1;
}
#Override
public void close() throws IOException {
channel.close();
}
#Override
public void flush() throws IOException {
channel.flush();
}
}
}
If you have any questions, please feel free to ask.

Java decompressing array of bytes

On server (C++), binary data is compressed using ZLib function:
compress2()
and it's sent over to client (Java).
On client side (Java), data should be decompressed using the following code snippet:
public static String unpack(byte[] packedBuffer) {
InflaterInputStream inStream = new InflaterInputStream(new ByteArrayInputStream( packedBuffer);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
int readByte;
try {
while((readByte = inStream.read()) != -1) {
outStream.write(readByte);
}
} catch(Exception e) {
JMDCLog.logError(" unpacking buffer of size: " + packedBuffer.length);
e.printStackTrace();
// ... the rest of the code follows
}
Problem is that when it tries to read in while loop it always throws:
java.util.zip.ZipException: invalid stored block lengths
Before I check for other possible causes can someone please tell me can I compress on one side with compress2 and decompress it on the other side using above code, so I can eliminate this as a problem? Also if someone has a possible clue about what might be wrong here (I know I didn't provide too much of of the code in here but projects are rather big.
Thanks.
I think the problem is not with unpack method but in packedBuffer content. Unpack works fine
public static byte[] pack(String s) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DeflaterOutputStream dout = new DeflaterOutputStream(out);
dout.write(s.getBytes());
dout.close();
return out.toByteArray();
}
public static void main(String[] args) throws Exception {
byte[] a = pack("123");
String s = unpack(a); // calls your unpack
System.out.println(s);
}
output
123
public static String unpack(byte[] packedBuffer) {
try (GZipInputStream inStream = new GZipInputStream(
new ByteArrayInputStream(packedBuffer));
ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {
inStream.transferTo(outStream);
//...
return outStream.toString(StandardCharsets.UTF_8);
} catch(Exception e) {
JMDCLog.logError(" unpacking buffer of size: " + packedBuffer.length);
e.printStackTrace();
throw new IllegalArgumentException(e);
}
}
ZLib is the zip format, hence a GZipInputStream is fine.
A you seem to expect the bytes to represent text, hence be in some encoding, add that encoding, Charset, to the conversion to String (which always holds Unicode).
Note, UTF-8 is the encoding of the bytes. In your case it might be an other encoding.
The ugly try-with-resources syntax closes the streams even on exception or here the return.
I rethrowed a RuntimeException as it seems dangerous to do something with no result.

Decompressed video file is not working in Java

Basically i compress video using the customized compressor class in Java. I have assembled my complete code snippets here. My actually problem is, generated video [ A.mp4] from the decompressed byte array is not running. I actually i got this compressor class code over the internet. As i new to Java platform, i am struggling to resolve this problem. Could you please any one help me on this.?
public class CompressionTest
{
public static void main(String[] args)
{
Compressor compressor = new Compressor();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis=null;
File file=null;
try
{
URL uri=CompressionTest.class.getResource("/Files/Video.mp4");
file=new File(uri.getPath());
fis = new FileInputStream(file);
}
catch ( FileNotFoundException fnfe )
{
System.out.println( "Unable to open input file");
}
try
{
byte[] videoBytes = getBytesFromFile(file);
System.out.println("CompressionVideoToCompress is: '" +videoBytes + "'");
byte[] bytesCompressed = compressor.compress(videoBytes);
System.out.println("bytesCompressed is: '" +bytesCompressed+ "'");
byte[] bytesDecompressed=compressor.decompress(bytesCompressed);
System.out.println("bytesDecompressed is: '" +bytesDecompressed+ "'");
FileOutputStream out = new FileOutputStream("A.mp4");
out.write(bytesDecompressed,0,bytesDecompressed.length-1);
out.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
System.out.println("bytesCompressed is: '");
}
}
public static byte[] getBytesFromFile(File file) throws IOException
{
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE) {
// File is too large
}
// Create the byte array to hold the data
byte[] bytes = new byte[1064];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0)
{
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
}
class Compressor
{
public Compressor()
{}
public byte[] compress(byte[] bytesToCompress)
{
Deflater deflater = new Deflater();
deflater.setInput(bytesToCompress);
deflater.finish();
byte[] bytesCompressed = new byte[Short.MAX_VALUE];
int numberOfBytesAfterCompression = deflater.deflate(bytesCompressed);
byte[] returnValues = new byte[numberOfBytesAfterCompression];
System.arraycopy
(
bytesCompressed,
0,
returnValues,
0,
numberOfBytesAfterCompression
);
return returnValues;
}
public byte[] decompress(byte[] bytesToDecompress)
{
Inflater inflater = new Inflater();
int numberOfBytesToDecompress = bytesToDecompress.length;
inflater.setInput
(
bytesToDecompress,
0,
numberOfBytesToDecompress
);
int compressionFactorMaxLikely = 3;
int bufferSizeInBytes =
numberOfBytesToDecompress
* compressionFactorMaxLikely;
byte[] bytesDecompressed = new byte[bufferSizeInBytes];
byte[] returnValues = null;
try
{
int numberOfBytesAfterDecompression = inflater.inflate(bytesDecompressed);
returnValues = new byte[numberOfBytesAfterDecompression];
System.arraycopy
(
bytesDecompressed,
0,
returnValues,
0,
numberOfBytesAfterDecompression
);
}
catch (DataFormatException dfe)
{
dfe.printStackTrace();
}
inflater.end();
return returnValues;
}
}
I've tested your code by compressing and decompressing a simple TXT file. The code is broken, since the compressed file, when uncompressed, is different from the original one.
Take for granted that the code is broken at least in the getBytesFromFile function. Its logic is tricky and troublesome, since it only allows files up to length 1064 and the check (throwing IOException when a longer file is read) does not work at all. The file gets read only partially and no exception is thrown.
What you are trying to achieve (file compression/decompression) can be done this way. I've tested it and it works, you just need this library.
import java.io.*;
import java.util.zip.*;
import org.apache.commons.io.IOUtils; // <-- get this from http://commons.apache.org/io/index.html
public class CompressionTest2 {
public static void main(String[] args) throws IOException {
File input = new File("input.txt");
File output = new File("output.bin");
Compression.compress(input, output);
File input2 = new File("input2.txt");
Compression.decompress(output, input2);
// At this point, input.txt and input2.txt should be equal
}
}
class Compression {
public static void compress(File input, File output) throws IOException {
FileInputStream fis = new FileInputStream(input);
FileOutputStream fos = new FileOutputStream(output);
GZIPOutputStream gzipStream = new GZIPOutputStream(fos);
IOUtils.copy(fis, gzipStream);
gzipStream.close();
fis.close();
fos.close();
}
public static void decompress(File input, File output) throws IOException {
FileInputStream fis = new FileInputStream(input);
FileOutputStream fos = new FileOutputStream(output);
GZIPInputStream gzipStream = new GZIPInputStream(fis);
IOUtils.copy(gzipStream, fos);
gzipStream.close();
fis.close();
fos.close();
}
}
This code doesn't come from "credible and/or official sources" but at least it works. :)
Moreover, in order to get more answers, adjust the title stating your real problem: your compressed files don't decompress the right way. There is no 'video' stuff here. Moreover, zipping a .mp4 file is no achievement (compression ratio will likely be around 99.99%).
Two tips:
1) Replace getBytesFromFile with a well known API call, either using Apache commons (IOUtils) or java 7 now provides such a method, too.
2) Test compress and decompress by writing a Junit test:
Create a random huge byte array, write it out, read it back and compare it with the created one.

Categories

Resources