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.
Related
I've found many ways of converting a file to a byte array and writing byte array to a file on storage.
What I want is to convert java.io.File to a byte array and then convert a byte array back to a java.io.File.
I don't want to write it out to storage like the following:
//convert array of bytes into file
FileOutputStream fileOuputStream = new FileOutputStream("C:\\testing2.txt");
fileOuputStream.write(bFile);
fileOuputStream.close();
I want to somehow do the following:
File myFile = ConvertfromByteArray(bytes);
Otherwise Try this :
Converting File To Bytes
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Temp {
public static void main(String[] args) {
File file = new File("c:/EventItemBroker.java");
byte[] b = new byte[(int) file.length()];
try {
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(b);
for (int i = 0; i < b.length; i++) {
System.out.print((char)b[i]);
}
} catch (FileNotFoundException e) {
System.out.println("File Not Found.");
e.printStackTrace();
}
catch (IOException e1) {
System.out.println("Error Reading The File.");
e1.printStackTrace();
}
}
}
Converting Bytes to File
public class WriteByteArrayToFile {
public static void main(String[] args) {
String strFilePath = "Your path";
try {
FileOutputStream fos = new FileOutputStream(strFilePath);
String strContent = "Write File using Java ";
fos.write(strContent.getBytes());
fos.close();
}
catch(FileNotFoundException ex) {
System.out.println("FileNotFoundException : " + ex);
}
catch(IOException ioe) {
System.out.println("IOException : " + ioe);
}
}
}
I think you misunderstood what the java.io.File class really represents. It is just a representation of the file on your system, i.e. its name, its path etc.
Did you even look at the Javadoc for the java.io.File class? Have a look here
If you check the fields it has or the methods or constructor arguments, you immediately get the hint that all it is, is a representation of the URL/path.
Oracle provides quite an extensive tutorial in their Java File I/O tutorial, with the latest NIO.2 functionality too.
With NIO.2 you can read it in one line using java.nio.file.Files.readAllBytes().
Similarly you can use java.nio.file.Files.write() to write all bytes in your byte array.
UPDATE
Since the question is tagged Android, the more conventional way is to wrap the FileInputStream in a BufferedInputStream and then wrap that in a ByteArrayInputStream.
That will allow you to read the contents in a byte[]. Similarly the counterparts to them exist for the OutputStream.
You can't do this. A File is just an abstract way to refer to a file in the file system. It doesn't contain any of the file contents itself.
If you're trying to create an in-memory file that can be referred to using a File object, you aren't going to be able to do that, either, as explained in this thread, this thread, and many other places..
Apache FileUtil gives very handy methods to do the conversion
try {
File file = new File(imagefilePath);
byte[] byteArray = new byte[file.length()]();
byteArray = FileUtils.readFileToByteArray(file);
}catch(Exception e){
e.printStackTrace();
}
There is no such functionality but you can use a temporary file by File.createTempFile().
File temp = File.createTempFile(prefix, suffix);
// tell system to delete it when vm terminates.
temp.deleteOnExit();
You cannot do it for File, which is primarily an intelligent file path. Can you refactor your code so that it declares the variables, and passes around arguments, with type OutputStream instead of FileOutputStream? If so, see classes java.io.ByteArrayOutputStream and java.io.ByteArrayInputStream
OutputStream outStream = new ByteArrayOutputStream();
outStream.write(whatever);
outStream.close();
byte[] data = outStream.toByteArray();
InputStream inStream = new ByteArrayInputStream(data);
...
1- Traditional way
The traditional conversion way is through using read() method of InputStream as the following:
public static byte[] convertUsingTraditionalWay(File file)
{
byte[] fileBytes = new byte[(int) file.length()];
try(FileInputStream inputStream = new FileInputStream(file))
{
inputStream.read(fileBytes);
}
catch (Exception ex)
{
ex.printStackTrace();
}
return fileBytes;
}
2- Java NIO
With Java 7, you can do the conversion using Files utility class of nio package:
public static byte[] convertUsingJavaNIO(File file)
{
byte[] fileBytes = null;
try
{
fileBytes = Files.readAllBytes(file.toPath());
}
catch (Exception ex)
{
ex.printStackTrace();
}
return fileBytes;
}
3- Apache Commons IO
Besides JDK, you can do the conversion using Apache Commons IO library in 2 ways:
3.1. IOUtils.toByteArray()
public static byte[] convertUsingIOUtils(File file)
{
byte[] fileBytes = null;
try(FileInputStream inputStream = new FileInputStream(file))
{
fileBytes = IOUtils.toByteArray(inputStream);
}
catch (Exception ex)
{
ex.printStackTrace();
}
return fileBytes;
}
3.2. FileUtils.readFileToByteArray()
public static byte[] convertUsingFileUtils(File file)
{
byte[] fileBytes = null;
try
{
fileBytes = FileUtils.readFileToByteArray(file);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return fileBytes;
}
Server side
#RequestMapping("/download")
public byte[] download() throws Exception {
File f = new File("C:\\WorkSpace\\Text\\myDoc.txt");
byte[] byteArray = new byte[(int) f.length()];
byteArray = FileUtils.readFileToByteArray(f);
return byteArray;
}
Client side
private ResponseEntity<byte[]> getDownload(){
URI end = URI.create(your url which server has exposed i.e. bla
bla/download);
return rest.getForEntity(end,byte[].class);
}
public static void main(String[] args) throws Exception {
byte[] byteArray = new TestClient().getDownload().getBody();
FileOutputStream fos = new
FileOutputStream("C:\\WorkSpace\\testClient\\abc.txt");
fos.write(byteArray);
fos.close();
System.out.println("file written successfully..");
}
//The file that you wanna convert into byte[]
File file=new File("/storage/0CE2-EA3D/DCIM/Camera/VID_20190822_205931.mp4");
FileInputStream fileInputStream=new FileInputStream(file);
byte[] data=new byte[(int) file.length()];
BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
bufferedInputStream.read(data,0,data.length);
//Now the bytes of the file are contain in the "byte[] data"
/*If you want to convert these bytes into a file, you have to write these bytes to a
certain location, then it will make a new file at that location if same named file is
not available at that location*/
FileOutputStream fileOutputStream =new FileOutputStream(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()+"/Video.mp4");
fileOutputStream.write(data);
/* It will write or make a new file named Video.mp4 in the "Download" directory of
the External Storage */
I have a requirement to create a zip file from input stream data, and before writing to zip I need to find the checksum for the input stream.
To do that I am using below codes:
private String writeZipFileToFS(List<ResponsePacks> attachmentList) throws IOException
{
File fileToWrite = new File(getZipPath() + "fileName.zip");
try
{
FileUtils.copyInputStreamToFile(compress(attachmentList), fileToWrite);
}
catch (IOException e)
{
throw e;
}
return fileName;
}
private InputStream compress(List<ResponsePacks> attachmentList)
{
byte buffer[] = new byte[2048];
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ZipOutputStream zipFileToSend = new ZipOutputStream(byteStream);
try
{
for (ResponsePacks info : attachmentList)
{
// only for successful requests files would need to be added
zipFileToSend.putNextEntry(new ZipEntry(info.getFileName()));
InputStream in = info.getFileContentStream();
getCheckSum(in, info.getFileName());
int length;
while ((length = in.read(buffer)) >= 0)
{
zipFileToSend.write(buffer, 0, length);
}
zipFileToSend.closeEntry();
}
zipFileToSend.close();
}
catch (IOException e)
{
throw e;
}
return new ByteArrayInputStream(byteStream.toByteArray());
}
private static void getCheckSum(InputStream is, String fileName)
{
byte[] dataCopy = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try
{
IOUtils.copy(is, outputStream);
dataCopy = outputStream.toByteArray();
printLog("Byte Array Size {}", dataCopy.length);
String checkSum = calculateChecksum(dataCopy);
printLog("Checksum for file {} {}", fileName, checkSum);
outputStream.flush();
outputStream.close();
}
catch (Exception e)
{
printLog("Error on calculationg checksum {}", e.getMessage());
}
}
private static String calculateChecksum(byte[] dataCopy)
{
try (ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(dataCopy)))
{
ZipEntry zipEntry;
MessageDigest digest = DigestUtils.getSha256Digest();
DWriter writer = new DWriter(digest);
while ((zipEntry = zipInputStream.getNextEntry()) != null)
{
byte[] entityData = IOUtils.toByteArray(zipInputStream);
if (!zipEntry.isDirectory())
{
writer.write(entityData);
}
}
if (writer.getChecksum() != null)
{
return writer.getChecksum();
}
}
catch (Exception e)
{
throw e;
}
return "";
}
static class DWriter
{
private final MessageDigest myDigest;
DWriter(MessageDigest digest)
{
myDigest = digest;
}
public void write(byte[] data)
{
myDigest.update(data);
}
public String getChecksum()
{
return new String(Hex.encodeHex(myDigest.digest()));
}
}
But problem is if I am adding code to calculate the checksum then zip file creating with empty content and if I am removing the checksum calculation code then zip file creating with proper contents.
And also when I check the log I found InputStream contents different contents but still I am getting the same checkSum (empty string) always as below:
Byte Array Size 20854
Checksum for file 20200910173919142.json e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Byte Array Size 14383
Checksum for file 1599752440405.zip e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
I am unable to find where I am doing wrong, due to which zip file is creating with empty content, and checkSum also creating same always.
Requesting to help me to find where I am doing wrong.
You consume twice the same inputstream: first you read it to get the checksum and the you read it again to write the zip entry.
getCheckSum(in, info.getFileName());
int length;
while ((length = in.read(buffer)) >= 0)
{
zipFileToSend.write(buffer, 0, length);
}
The second time you're trying to read, there's nothing to read anymore, so nothing gets written into the zip entry.
Some input streams can be reset and read multiple times, if that's not the case here you would need to save the data into a ByteArrayOutputStream (as you're already doing inside the getCheckSum() method), and then you could read that data multiple times.
I am working on project where I have to download attachments that i receive from server. I have to exploit base64 data and convert it to the appropriate type and download it. It works for me perfectly with images ( base 64 => bytes => bitmap ) but I find troubles with other types ( txt , pdf ..etc )
try this
try {
File sdcard = Environment.getExternalStorageDirectory();
File file = new File(sdcard,"test.pdf");
File new_file_name = new File(sdcard,"new_file.pdf");
byte[] input_file = IOUtil.readFile(file);
byte[] encodedBytes = Base64.encode(input_file,URL_SAFE);
String encodedString = new String(encodedBytes);
byte[] decodedBytes = Base64.decode(encodedString.getBytes(),URL_SAFE);
FileOutputStream fos = new FileOutputStream(new_file_name);
fos.write(decodedBytes);
fos.flush();
fos.close();
}catch (Exception e)
{
Log.e("ERROR",e.toString());
}
And IOUtil class
public class IOUtil {
public static byte[] readFile(String file) throws IOException {
return readFile(new File(file));
}
public static byte[] readFile(File file) throws IOException {
// Open file
RandomAccessFile f = new RandomAccessFile(file, "r");
try {
// Get and check length
long longlength = f.length();
int length = (int) longlength;
if (length != longlength)
throw new IOException("File size >= 2 GB");
// Read file and return data
byte[] data = new byte[length];
f.readFully(data);
return data;
} finally {
f.close();
}
}
}
this code contain both encode and decode parts
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.
From a DB2 table I've got blob which I'm converting to a byte array so I can work with it. I need to take the byte array and create a PDF out of it.
This is what I have:
static void byteArrayToFile(byte[] bArray) {
try {
// Create file
FileWriter fstream = new FileWriter("out.pdf");
BufferedWriter out = new BufferedWriter(fstream);
for (Byte b: bArray) {
out.write(b);
}
out.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
But the PDF it creates is not right, it has a bunch of black lines running from top to bottom on it.
I was actually able to create the correct PDF by writing a web application using essentially the same process. The primary difference between the web application and the code about was this line:
response.setContentType("application/pdf");
So I know the byte array is a PDF and it can be done, but my code in byteArrayToFile won't create a clean PDF.
Any ideas on how I can make it work?
Sending your output through a FileWriter is corrupting it because the data is bytes, and FileWriters are for writing characters. All you need is:
OutputStream out = new FileOutputStream("out.pdf");
out.write(bArray);
out.close();
One can utilize the autoclosable interface that was introduced in java 7.
try (OutputStream out = new FileOutputStream("out.pdf")) {
out.write(bArray);
}
Read from file or string to bytearray.
byte[] filedata = null;
String content = new String(bytearray);
content = content.replace("\r", "").replace("\uf8ff", "").replace("'", "").replace("\"", "").replace("`", "");
String[] arrOfStr = content.split("\n");
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
try (PDPageContentStream cs = new PDPageContentStream(document, page)) {
// setting font family and font size
cs.beginText();
cs.setFont(PDType1Font.HELVETICA, 14);
cs.setNonStrokingColor(Color.BLACK);
cs.newLineAtOffset(20, 750);
for (String str: arrOfStr) {
cs.newLineAtOffset(0, -15);
cs.showText(str);
}
cs.newLine();
cs.endText();
}
document.save(znaFile);
document.close();
public static String getPDF() throws IOException {
File file = new File("give complete path of file which must be read");
FileInputStream stream = new FileInputStream(file);
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead;enter code here
while ((bytesRead = stream.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
System.out.println("it came back"+baos);
byte[] buffer1= baos.toByteArray();
String fileName = "give your filename with location";
//stream.close();
FileOutputStream outputStream =
new FileOutputStream(fileName);
outputStream.write(buffer1);
return fileName;
}