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) {
Related
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
This is my test program. I need it to apply somewhere.This may be small, sorry for that. But I'm a starter still. So kindly help me.
try{
File file1 = new File("c:\\Users\\prasad\\Desktop\\bugatti.jpg");
File file2 = new File("c:\\Users\\prasad\\Desktop\\hello.jpg");
file2.createNewFile();
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file1)));
String data = null;
StringBuilder imageBuild = new StringBuilder();
while((data = reader.readLine())!=null){
imageBuild.append(data);
}
reader.close();
BufferedWriter writer = new BufferedWriter(new PrintWriter(new FileOutputStream(file2)));
writer.write(imageBuild.toString());
writer.close();
}catch(IOException e){
e.printStackTrace();
}
This is file1
and This is file2
You can do either of these two:
private static void copyFile(File source, File dest) throws IOException {
Files.copy(source.toPath(), dest.toPath());
}
or maybe this if you want to use streams:
private static void copyFile(File source, File dest)
throws IOException {
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(source);
output = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buf)) > 0) {
output.write(buf, 0, bytesRead);
}
} finally {
input.close();
output.close();
}
}
Images do not contain lines or even characters. You therefore should not be using readLine() or even Readers or Writers. You should rewrite the copy loop using input and output streams directly.
I used the following snippet to download pdf files ( I took it from here , credits to Josh M)
public final class FileDownloader {
private FileDownloader(){}
public static void main(String args[]) throws IOException{
download("http://pdfobject.com/pdf/sample.pdf", new File("sample.pdf"));
}
public static void download(final String url, final File destination) throws IOException {
final URLConnection connection = new URL(url).openConnection();
connection.setConnectTimeout(60000);
connection.setReadTimeout(60000);
connection.addRequestProperty("User-Agent", "Mozilla/5.0");
final FileOutputStream output = new FileOutputStream(destination, false);
final byte[] buffer = new byte[2048];
int read;
final InputStream input = connection.getInputStream();
while((read = input.read(buffer)) > -1)
output.write(buffer, 0, read);
output.flush();
output.close();
input.close();
}
}
It works perfect with pdf files. However, as I encountered a "bad file" ... I do not know what the extension of that file is , but it appears that I fell into infinite loop of while((read = input.read(buffer)) > -1). How can I improve this snippet to discard any kind of inappropriate files (non pdfs)?
There is a question with the similar issue: Infinite Loop in Input Stream.
Check out a possible solution: Abort loop after fixed time.
You could try setting a timeout for the connection: Java URLConnection Timeout.
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.
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.