I've implemented some GzipUtil which works pretty good and looks like this:
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPInputStream;
public class GzipUtil {
public static void unzip(String putBase64EncodedGzippedStringHere) throws Base64DecodingException {
byte[] compressed = Base64.decode(putBase64EncodedGzippedStringHere);
if ((compressed == null) || (compressed.length == 0)) {
throw new IllegalArgumentException("Cannot unzip null or empty bytes");
}
if (!isZipped(compressed)) {
System.out.println(compressed);
}
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(compressed)) {
try (GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream)) {
try (InputStreamReader inputStreamReader =
new InputStreamReader(gzipInputStream, StandardCharsets.UTF_8)) {
try (BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
StringBuilder output = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
output.append(line);
System.out.println(output.toString());
}
}
}
}
} catch (IOException e) {
throw new RuntimeException("Failed to unzip content", e);
}
}
public static boolean isZipped(final byte[] compressed) {
return (compressed[0] == (byte) (GZIPInputStream.GZIP_MAGIC))
&& (compressed[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8));
}
}
Now I've got some other code that consumes a RabbitMQ queue like this:
ConnectionFactory rabbitMqConnectionFactory = new ConnectionFactory();
rabbitMqConnectionFactory.setHost("MyHostname");
rabbitMqConnectionFactory.setPort(5672);
rabbitMqConnectionFactory.setUsername("MyUsername");
rabbitMqConnectionFactory.setPassword("MyPassword");
rabbitMqConnectionFactory.setVirtualHost("MyVirtualHost");
Connection physicalSocketConnectionToRabbitMq = rabbitMqConnectionFactory.newConnection();
Channel messageChannel = physicalSocketConnectionToRabbitMq.createChannel();
// if the queue already exists, it won't do anything, it just skips the operation
messageChannel.queueDeclare(
"MyQueueName", //queue
true, //durable
false, //exclusive
false, //autoDelete
null //arguments
);
DeliverCallback deliverCallback = new DeliverCallback() {
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println("consumerTag=" + consumerTag);
System.out.println("exchangeName=" + message.getEnvelope().getExchange() );
System.out.println("routingKey=" + message.getEnvelope().getRoutingKey() );
System.out.println("deliveryTag=" + message.getEnvelope().getDeliveryTag() );
byte[] data = message.getBody();
if (data == null) {
System.err.println("body is null");
}
else {
System.err.println("body is not null: " + data);
try {
GzipUtil.unzip( new String(data) );
}
catch (Exception e) {
System.err.println("Exception: " + e);
}
}
}
};
messageChannel.basicConsume(
"MyQueueName",
autoAcknowledge,
deliverCallback,
new CancelCallback() {
public void handle(String consumerTag) throws IOException {
//nothing to do
}
}
);
If I run this code, the output looks like this:
body is not null: [B#5f571234
consumerTag=XXX
exchangeName=XXX
routingKey=tomato_gzip_b64
deliveryTag=1
message.getBody() returns some byte array. As I understood, I have to use new String to make it a decoded string:
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
System.out.println("decodedBytes=" + decodedBytes);
String decodedString = new String(decodedBytes);
System.out.println("decodedString=" + decodedString);
It seems like I missed something, because my GzipUtil returns nothing when I call GzipUtil.unzip( new String(data) );! Does anyone know why?
String payload = new String(message.getBody(), StandardCharsets.UTF_8);
Even if the message content is a JSON file inside a GZIP archive, the payload is still read as a string and with UTF-8 as the default charset. Then the correct content comes out the back and can be processed further.
From this string you can make a JSON file again, which can also be zipped again.
Good hint from VGA (comment above)!
Related
I want to save a file to the internal storage by getting the text inputted from EditText. Then I want the same file to return the inputted text in String form and save it to another String which is to be used later.
Here's the code:
package com.omm.easybalancerecharge;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText num = (EditText) findViewById(R.id.sNum);
Button ch = (Button) findViewById(R.id.rButton);
TelephonyManager operator = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String opname = operator.getNetworkOperatorName();
TextView status = (TextView) findViewById(R.id.setStatus);
final EditText ID = (EditText) findViewById(R.id.IQID);
Button save = (Button) findViewById(R.id.sButton);
final String myID = ""; //When Reading The File Back, I Need To Store It In This String For Later Use
save.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Get Text From EditText "ID" And Save It To Internal Memory
}
});
if (opname.contentEquals("zain SA")) {
status.setText("Your Network Is: " + opname);
} else {
status.setText("No Network");
}
ch.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Read From The Saved File Here And Append It To String "myID"
String hash = Uri.encode("#");
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:*141*" + /*Use The String With Data Retrieved Here*/ num.getText()
+ hash));
startActivity(intent);
}
});
}
I have included comments to help you further analyze my points as to where I want the operations to be done/variables to be used.
Hope this might be useful to you.
Write File:
private void writeToFile(String data,Context context) {
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput("config.txt", Context.MODE_PRIVATE));
outputStreamWriter.write(data);
outputStreamWriter.close();
}
catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
}
Read File:
private String readFromFile(Context context) {
String ret = "";
try {
InputStream inputStream = context.openFileInput("config.txt");
if ( inputStream != null ) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ( (receiveString = bufferedReader.readLine()) != null ) {
stringBuilder.append("\n").append(receiveString);
}
inputStream.close();
ret = stringBuilder.toString();
}
}
catch (FileNotFoundException e) {
Log.e("login activity", "File not found: " + e.toString());
} catch (IOException e) {
Log.e("login activity", "Can not read file: " + e.toString());
}
return ret;
}
For those looking for a general strategy for reading and writing a string to file:
First, get a file object
You'll need the storage path. For the internal storage, use:
File path = context.getFilesDir();
For the external storage (SD card), use:
File path = context.getExternalFilesDir(null);
Then create your file object:
File file = new File(path, "my-file-name.txt");
Write a string to the file
FileOutputStream stream = new FileOutputStream(file);
try {
stream.write("text-to-write".getBytes());
} finally {
stream.close();
}
Or with Google Guava
String contents = Files.toString(file, StandardCharsets.UTF_8);
Read the file to a string
int length = (int) file.length();
byte[] bytes = new byte[length];
FileInputStream in = new FileInputStream(file);
try {
in.read(bytes);
} finally {
in.close();
}
String contents = new String(bytes);
Or if you are using Google Guava
String contents = Files.toString(file,"UTF-8");
For completeness I'll mention
String contents = new Scanner(file).useDelimiter("\\A").next();
which requires no libraries, but benchmarks 50% - 400% slower than the other options (in various tests on my Nexus 5).
Notes
For each of these strategies, you'll be asked to catch an IOException.
The default character encoding on Android is UTF-8.
If you are using external storage, you'll need to add to your manifest either:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
or
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Write permission implies read permission, so you don't need both.
public static void writeStringAsFile(final String fileContents, String fileName) {
Context context = App.instance.getApplicationContext();
try {
FileWriter out = new FileWriter(new File(context.getFilesDir(), fileName));
out.write(fileContents);
out.close();
} catch (IOException e) {
Logger.logError(TAG, e);
}
}
public static String readFileAsString(String fileName) {
Context context = App.instance.getApplicationContext();
StringBuilder stringBuilder = new StringBuilder();
String line;
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(new File(context.getFilesDir(), fileName)));
while ((line = in.readLine()) != null) stringBuilder.append(line);
} catch (FileNotFoundException e) {
Logger.logError(TAG, e);
} catch (IOException e) {
Logger.logError(TAG, e);
}
return stringBuilder.toString();
}
Just a a bit modifications on reading string from a file method for more performance
private String readFromFile(Context context, String fileName) {
if (context == null) {
return null;
}
String ret = "";
try {
InputStream inputStream = context.openFileInput(fileName);
if ( inputStream != null ) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
int size = inputStream.available();
char[] buffer = new char[size];
inputStreamReader.read(buffer);
inputStream.close();
ret = new String(buffer);
}
}catch (Exception e) {
e.printStackTrace();
}
return ret;
}
The Kotlin way by using builtin Extension function on File
Write: yourFile.writeText(textFromEditText)
Read: yourFile.readText()
check the below code.
Reading from a file in the filesystem.
FileInputStream fis = null;
try {
fis = context.openFileInput(fileName);
InputStreamReader isr = new InputStreamReader(fis);
// READ STRING OF UNKNOWN LENGTH
StringBuilder sb = new StringBuilder();
char[] inputBuffer = new char[2048];
int l;
// FILL BUFFER WITH DATA
while ((l = isr.read(inputBuffer)) != -1) {
sb.append(inputBuffer, 0, l);
}
// CONVERT BYTES TO STRING
String readString = sb.toString();
fis.close();
catch (Exception e) {
} finally {
if (fis != null) {
fis = null;
}
}
below code is to write the file in to internal filesystem.
FileOutputStream fos = null;
try {
fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
fos.write(stringdatatobestoredinfile.getBytes());
fos.flush();
fos.close();
} catch (Exception e) {
} finally {
if (fos != null) {
fos = null;
}
}
I think this will help you.
I'm a bit of a beginner and struggled getting this to work today.
Below is the class that I ended up with. It works but I was wondering how imperfect my solution is. Anyway, I was hoping some of you more experienced folk might be willing to have a look at my IO class and give me some tips. Cheers!
public class HighScore {
File data = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator);
File file = new File(data, "highscore.txt");
private int highScore = 0;
public int readHighScore() {
try {
BufferedReader br = new BufferedReader(new FileReader(file));
try {
highScore = Integer.parseInt(br.readLine());
br.close();
} catch (NumberFormatException | IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
try {
file.createNewFile();
} catch (IOException ioe) {
ioe.printStackTrace();
}
e.printStackTrace();
}
return highScore;
}
public void writeHighScore(int highestScore) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
bw.write(String.valueOf(highestScore));
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Kotlin
class FileReadWriteService {
private var context:Context? = ContextHolder.instance.appContext
fun writeFileOnInternalStorage(fileKey: String, sBody: String) {
val file = File(context?.filesDir, "files")
try {
if (!file.exists()) {
file.mkdir()
}
val fileToWrite = File(file, fileKey)
val writer = FileWriter(fileToWrite)
writer.append(sBody)
writer.flush()
writer.close()
} catch (e: Exception) {
Logger.e(classTag, e)
}
}
fun readFileOnInternalStorage(fileKey: String): String {
val file = File(context?.filesDir, "files")
var ret = ""
try {
if (!file.exists()) {
return ret
}
val fileToRead = File(file, fileKey)
val reader = FileReader(fileToRead)
ret = reader.readText()
reader.close()
} catch (e: Exception) {
Logger.e(classTag, e)
}
return ret
}
}
the first thing we need is the permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
so in an asyncTask Kotlin class, we treat the creation of the file
import android.os.AsyncTask
import android.os.Environment
import android.util.Log
import java.io.*
class WriteFile: AsyncTask<String, Int, String>() {
private val mFolder = "/MainFolder"
lateinit var folder: File
internal var writeThis = "string to cacheApp.txt"
internal var cacheApptxt = "cacheApp.txt"
override fun doInBackground(vararg writethis: String): String? {
val received = writethis[0]
if(received.isNotEmpty()){
writeThis = received
}
folder = File(Environment.getExternalStorageDirectory(),"$mFolder/")
if(!folder.exists()){
folder.mkdir()
val readME = File(folder, cacheApptxt)
val file = File(readME.path)
val out: BufferedWriter
try {
out = BufferedWriter(FileWriter(file, true), 1024)
out.write(writeThis)
out.newLine()
out.close()
Log.d("Output_Success", folder.path)
} catch (e: Exception) {
Log.d("Output_Exception", "$e")
}
}
return folder.path
}
override fun onPostExecute(result: String) {
super.onPostExecute(result)
if(result.isNotEmpty()){
//implement an interface or do something
Log.d("onPostExecuteSuccess", result)
}else{
Log.d("onPostExecuteFailure", result)
}
}
}
Of course if you are using Android above Api 23, you must handle the request to allow writing to device memory. Something like this
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class ReadandWrite {
private val mREAD = 9
private val mWRITE = 10
private var readAndWrite: Boolean = false
fun readAndwriteStorage(ctx: Context, atividade: AppCompatActivity): Boolean {
if (Build.VERSION.SDK_INT < 23) {
readAndWrite = true
} else {
val mRead = ContextCompat.checkSelfPermission(ctx, Manifest.permission.READ_EXTERNAL_STORAGE)
val mWrite = ContextCompat.checkSelfPermission(ctx, Manifest.permission.WRITE_EXTERNAL_STORAGE)
if (mRead != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(atividade, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), mREAD)
} else {
readAndWrite = true
}
if (mWrite != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(atividade, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), mWRITE)
} else {
readAndWrite = true
}
}
return readAndWrite
}
}
then in an activity, execute the call.
var pathToFileCreated = ""
val anRW = ReadandWrite().readAndwriteStorage(this,this)
if(anRW){
pathToFileCreated = WriteFile().execute("onTaskComplete").get()
Log.d("pathToFileCreated",pathToFileCreated)
}
We can use this code to write String to a file
public static void writeTextToFile(final String filename, final String data) {
File file = new File(filename);
try {
FileOutputStream stream = new FileOutputStream(file);
stream.write(data.getBytes());
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Then in the Main code, we use this, for example
writeTextToFile(getExternalFilesDir("/").getAbsolutePath() + "/output.txt", "my-example-text");
After that, check the file at Android/data/<package-name>/files.
The easiest way to append to a text file in kotlin:
val directory = File(context.filesDir, "LogsToSendToNextMunich").apply {
mkdirs()
}
val file = File(directory,"Logs.txt")
file.appendText("You new text")
If you want to just write to the file:
yourFile.writeText("You new text")
writing anything to the files, using bytes:
FileOutputStream(file).use {
it.write("Some text for example".encodeToByteArray())
}
I know Mule has great support for gzip compression of data using the element. However the client now wants zip compression since the file has to be placed on an FTP as a zip compressed file :(
I encounter difficulties in mule with following scenario:
I created a Spring bean where a file comes in. I want to compress this file using the ZipOutputStream class and pass it towards our ftp.
This is my flow configuration:
<flow name="testFlow" initialState="stopped">
<file:inbound-endpoint path="${home.dir}/out" moveToDirectory="${hip.dir}/out/hist" fileAge="10000" responseTimeout="10000" connector-ref="input"/>
<component>
<spring-object bean="zipCompressor"/>
</component>
<set-variable value="#[message.inboundProperties.originalFilename]" variableName="originalFilename" />
<ftp:outbound-endpoint host="${ftp.host}" port="${ftp.port}" user="${ftp.username}" password="${ftp.password}" path="${ftp.root.out}" outputPattern="#[flowVars['originalFilename']].zip" />
</flow>
This is the code of my zipCompressor:
#Component
public class ZipCompressor implements Callable {
private static final Logger LOG = LogManager.getLogger(ZipCompressor.class.getName());
#Override
#Transactional
public Object onCall(MuleEventContext eventContext) throws Exception {
if (eventContext.getMessage().getPayload() instanceof File) {
final File srcFile = (File) eventContext.getMessage().getPayload();
final String fileName = srcFile.getName();
final File zipFile = new File(fileName + ".zip");
try {
// create byte buffer
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
FileInputStream fis = new FileInputStream(srcFile);
// begin writing a new ZIP entry, positions the stream to the start of the entry data
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
// close the InputStream
fis.close();
// close the ZipOutputStream
zos.close();
}
catch (IOException ioe) {
LOG.error("Error creating zip file" + ioe);
}
eventContext.getMessage().setPayload(zipFile);
}
return eventContext.getMessage();
}
}
I wrote a unit test and the compression works great. A file is indeed transferred to the FTP with the correct name, but the zip file is invalid and by opening it in NotePad++, it contains just the original file name.
I think I'm doing something wrong with passing the zip file back to the mule flow, but I'm stuck at the moment so any help would be greatly appreciated!
I have implemented the transformer for this
package com.test.transformer;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.mule.api.MuleMessage;
import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractMessageTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ZipTransformer
extends AbstractMessageTransformer
{
private static final Logger log = LoggerFactory.getLogger(ZipTransformer.class);
public static final int DEFAULT_BUFFER_SIZE = 32768;
public static byte[] MAGIC = { 'P', 'K', 0x3, 0x4 };
public ZipTransformer()
{
registerSourceType(InputStream.class);
registerSourceType(byte[].class);
}
public Object transformMessage(MuleMessage message, String outputEncoding)
throws TransformerException
{
Object payload = message.getPayload();
try{
byte[] data;
if (payload instanceof byte[])
{
data = (byte[]) payload;
}
else if (payload instanceof InputStream) {
data = IOUtils.toByteArray((InputStream)payload);
}
else if (payload instanceof String)
{
data = ((String) payload).getBytes(outputEncoding);
}
else
{
data = muleContext.getObjectSerializer().serialize(payload);
}
return compressByteArray(data);
}catch (Exception ioex)
{
throw new TransformerException(this, ioex);
}
}
public Object compressByteArray(byte[] bytes) throws IOException
{
if (bytes == null || isCompressed(bytes))
{
if (logger.isDebugEnabled())
{
logger.debug("Data already compressed; doing nothing");
}
return bytes;
}
if (logger.isDebugEnabled())
{
logger.debug("Compressing message of size: " + bytes.length);
}
ByteArrayOutputStream baos = null;
ZipOutputStream zos = null;
try
{
baos = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
zos = new ZipOutputStream(baos);
zos.putNextEntry(new ZipEntry("test.txt"));
zos.write(bytes, 0, bytes.length);
zos.finish();
zos.close();
byte[] compressedByteArray = baos.toByteArray();
baos.close();
if (logger.isDebugEnabled())
{
logger.debug("Compressed message to size: " + compressedByteArray.length);
}
return compressedByteArray;
}
catch (IOException ioex)
{
throw ioex;
}
finally
{
IOUtils.closeQuietly(zos);
IOUtils.closeQuietly(baos);
}
}
public boolean isCompressed(byte[] bytes) throws IOException
{
if ((bytes == null) || (bytes.length < 4 ))
{
return false;
}
else
{
for (int i = 0; i < MAGIC.length; i++) {
if (bytes[i] != MAGIC[i]) {
return false;
}
}
return true;
}
}
}
Used it as
<custom-transformer class="com.test.transformer.ZipTransformer" doc:name="file zip transformer"/>
As of now sets file name as test.txt. you can change is using any property or variable.
Hope this helps.
A simpler way to do it is to use the gzip transformer in mule to compress the file. Note that you have to do it through the xml.
<gzip-compress-transformer/>
In the ZipTransformer constructor, the following is deprecated.
registerSourceType(InputStream.class);
registerSourceType(byte[].class);
Use this instead:
registerSourceType(DataTypeFactory.create(InputStream.class));
registerSourceType(DataTypeFactory.create(byte[].class));
I have byte[] zipFileAsByteArray
This zip file has rootDir --|
| --- Folder1 - first.txt
| --- Folder2 - second.txt
| --- PictureFolder - image.png
What I need is to get two txt files and read them, without saving any files on disk. Just do it in memory.
I tried something like this:
ByteArrayInputStream bis = new ByteArrayInputStream(processZip);
ZipInputStream zis = new ZipInputStream(bis);
Also I will need to have separate method go get picture. Something like this:
public byte[]image getImage(byte[] zipContent);
Can someone help me with idea or good example how to do that ?
Here is an example:
public static void main(String[] args) throws IOException {
ZipFile zip = new ZipFile("C:\\Users\\mofh\\Desktop\\test.zip");
for (Enumeration e = zip.entries(); e.hasMoreElements(); ) {
ZipEntry entry = (ZipEntry) e.nextElement();
if (!entry.isDirectory()) {
if (FilenameUtils.getExtension(entry.getName()).equals("png")) {
byte[] image = getImage(zip.getInputStream(entry));
//do your thing
} else if (FilenameUtils.getExtension(entry.getName()).equals("txt")) {
StringBuilder out = getTxtFiles(zip.getInputStream(entry));
//do your thing
}
}
}
}
private static StringBuilder getTxtFiles(InputStream in) {
StringBuilder out = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
try {
while ((line = reader.readLine()) != null) {
out.append(line);
}
} catch (IOException e) {
// do something, probably not a text file
e.printStackTrace();
}
return out;
}
private static byte[] getImage(InputStream in) {
try {
BufferedImage image = ImageIO.read(in); //just checking if the InputStream belongs in fact to an image
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
return baos.toByteArray();
} catch (IOException e) {
// do something, it is not a image
e.printStackTrace();
}
return null;
}
Keep in mind though I am checking a string to diferentiate the possible types and this is error prone. Nothing stops me from sending another type of file with an expected extension.
You can do something like:
public static void main(String args[]) throws Exception
{
//bis, zis as you have
try{
ZipEntry file;
while((file = zis.getNextEntry())!=null) // get next file and continue only if file is not null
{
byte b[] = new byte[(int)file.getSize()]; // create array to read.
zis.read(b); // read bytes in b
if(file.getName().endsWith(".txt")){
// read files. You have data in `b`
}else if(file.getName().endsWith(".png")){
// process image
}
}
}
finally{
zis.close();
}
}
You can use below code.
But need to make sure that you S3 Bucket initial setup.
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
import com.amazonaws.services.s3.model.S3Object;
import java.io.*;
import static com.amazonaws.regions.Regions.US_EAST_1;
public class GetObject2 {
public static void main(String[] args) throws IOException {
String bucketName = "Give Yout Bucket Name";
String key = "Give your String Key";
S3Object fullObject = null, objectPortion = null, headerOverrideObject = null;
try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(US_EAST_1)
.withCredentials(new ProfileCredentialsProvider())
.build();
// Get an object and print its contents.
System.out.println("Downloading an object");
fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key));
System.out.println("Content-Type: " + fullObject.getObjectMetadata().getContentType());
System.out.println("Content: ");
displayTextInputStream(fullObject.getObjectContent());
File localFile = new File("C:\\awstest.zip");
ObjectMetadata object = s3Client.getObject(new GetObjectRequest(bucketName, key), localFile);
// Get a range of bytes from an object and print the bytes.
GetObjectRequest rangeObjectRequest = new GetObjectRequest(bucketName, key)
.withRange(0, 9);
objectPortion = s3Client.getObject(rangeObjectRequest);
System.out.println("Printing bytes retrieved.");
displayTextInputStream(objectPortion.getObjectContent());
// Get an entire object, overriding the specified response headers, and print the object's content.
ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides()
.withCacheControl("No-cache")
.withContentDisposition("attachment; filename=example.txt");
GetObjectRequest getObjectRequestHeaderOverride = new GetObjectRequest(bucketName, key)
.withResponseHeaders(headerOverrides);
headerOverrideObject = s3Client.getObject(getObjectRequestHeaderOverride);
displayTextInputStream(headerOverrideObject.getObjectContent());
} catch (AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
} catch (SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
} finally {
// To ensure that the network connection doesn't remain open, close any open input streams.
if (fullObject != null) {
fullObject.close();
}
if (objectPortion != null) {
objectPortion.close();
}
if (headerOverrideObject != null) {
headerOverrideObject.close();
}
}
}
static void displayTextInputStream(InputStream input) throws IOException {
// Read the text input stream one line at a time and display each line.
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
System.out.println();
}
}
i'm trying to ensure an output File integrity in case of disk out of space , network problem ,or any anyException that might occur during the streaming to file process .
is there a way to precalculate the FileStream checkSum before writing to disk then check if the file was written properly.
it sounds a bit nonsensical for me , that a system validates the integrity of its own exported XML through checkSum , normaly it's the job of the other end to verify if the the consumed file lives up to the file produced by the other system .
but it's a requirement i have to implement.
her's the stream i write as a file :
String xmlTransfer ="";
File testFile = new File("testFile.xml");
InputStream in = new ByteArrayInputStream(xmlTransfer.getBytes("utf-8"));
FileOutputStream out = new FileOutputStream(testFile)
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.close();
in.close();
No, you can't figure out how much data will come from a stream in advance. That's simply not how streams are meant to work.
What you could do, if you are writing both ends of the code, is to first calculate the file size on the sending end and send that before sending the file contents itself.
The best way is to catch exception. If something go wrong an exception will be launched and you could remove the partially written file in this case.
A second way is to have a in-memory stream before writing down to the filesystem but it consumes memory.
A third way is to ensure the destination disk capacity (new File(path).getFreeSpace())
The MD5 check sounds too slow for me in regards of the question.
try this :
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.MessageDigest;
public class CheckSumFileTest
{
private File buildChecksumFile(File fileToCheck, String filePrefix, String checksumAlgorithm) throws Exception
{
String checksum = null;
File checksumFile = null;
String tempDir = System.getProperty("java.io.tmpdir");
try {
checksumFile = new File(tempDir, filePrefix+"."+ checksumAlgorithm.toLowerCase());
checksumFile.createNewFile();
checksumFile.deleteOnExit();
} catch (Exception e1) {
e1.printStackTrace();
throw e1;
}
FileWriter fw = null;
try {
checksum = checkSum(fileToCheck,checksumAlgorithm);
fw = new FileWriter(checksumFile);
fw.write(checksum);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
finally
{
if(fw !=null)
fw.close();
}
return checksumFile;
}
private static String checkSum(File file, String checksumAlgorithm) throws Exception
{
MessageDigest digest = MessageDigest.getInstance(checksumAlgorithm);
InputStream input = null;
StringBuffer sb = new StringBuffer();
try{
input = new FileInputStream(file);
byte[] buffer = new byte[8192];
do {
int read = input.read(buffer);
if(read <= 0)
break;
digest.update(buffer, 0, read);
} while(true);
byte[] sum = digest.digest();
for (int i = 0; i < sum.length; i++) {
sb.append(Integer.toString((sum[i] & 0xff) + 0x100, 16).substring(1));
}
}catch(IOException io)
{
}finally{
if(input != null)
input.close();
}
return sb.toString();
}
private static String checkSumInStream(InputStream stream, String checksumAlgorithm) throws Exception
{
MessageDigest digest = MessageDigest.getInstance(checksumAlgorithm);
InputStream input = null;
StringBuffer sb = new StringBuffer();
try{
input = stream;
byte[] buffer = new byte[8192];
do {
int read = input.read(buffer);
if(read <= 0)
break;
digest.update(buffer, 0, read);
} while(true);
byte[] sum = digest.digest();
for (int i = 0; i < sum.length; i++) {
sb.append(Integer.toString((sum[i] & 0xff) + 0x100, 16).substring(1));
}
}catch(IOException io)
{
}finally{
if(input != null)
input.close();
}
return sb.toString();
}
private boolean checkIntegrity(String targetFileName, String checksumFileName, String checksumAlgorithm) throws Exception
{
FileInputStream stream = null;
BufferedReader br = null;
InputStreamReader ipsr = null;
File checksumFile = null;
String checksumString="";
File targetFile = new File(targetFileName);
try{
checksumFile = new File(checksumFileName);
stream = new FileInputStream(checksumFile);
ipsr = new InputStreamReader(stream);
br = new BufferedReader(ipsr);
//In checksum file : only one line to read
checksumString = br.readLine();
}finally
{
if(br != null)
br.close();
if(ipsr != null)
ipsr.close();
if(stream != null)
stream.close();
}
if(checksumString.equals(checkSum(targetFile,checksumAlgorithm)))
{
return true;
}
else
{
return false;
}
}
/**
* #param args
*/
public static void main(String[] args)
{
String str = "Amine";
InputStream stream = new ByteArrayInputStream(str.getBytes());
//step1
try {
System.out.println(checkSumInStream(stream,"MD5"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//step2
File file = new File("c:/test.txt");
// if file doesnt exists, then create it
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
FileWriter fw;
BufferedWriter bw;
try {
fw = new FileWriter(file.getAbsoluteFile());
bw = new BufferedWriter(fw);
bw.write(str);
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(checkSum(file, "MD5"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Done");
}
}
You should check by MD5, not file size
You can calculate your MD5 while you're reading the stream.
See https://stackoverflow.com/a/304350/3230038
Then, after saving the file, you can generate the md5 again and compare
UPDATE - here's my more detailed idea for this. I am assuming that you just want to calculate the MD5 without having to bring the whole byte[] into memory. In this case, I think you have 2 options
calculate MD5 on the fly, as you're saving, then after saving, check md5 again (if you're on linux you can just use md5sum)
calculate MD5 in a first pass, then save the file in a second pass.
for example
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
public class MD5OnTheFly {
/**
* #param args
* #throws NoSuchAlgorithmException
* #throws IOException
*/
public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
long ini = System.currentTimeMillis();
File file = new File("/home/leoks/Downloads/VirtualBox-4.3.0.tar");
System.out.println("size:"+file.length());
InputStream is = new FileInputStream(file);
MessageDigest md = MessageDigest.getInstance("MD5");
DigestInputStream dis = new DigestInputStream(is, md);
IOUtils.copy(dis, new NullOutputStream());
byte[] digest = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
String hex = Integer.toHexString(0xff & digest[i]);
if (hex.length() == 1)
hexString.append('0');
hexString.append(hex);
}
System.out.println(hexString);
long end = System.currentTimeMillis();
System.out.println(end-ini+" millis");
}
}
returns
410859520
dda81aea75a83b1489662c6bcd0677e4
1413 millis
and then
[leoks#home ~]$ md5sum /home/leoks/Downloads/VirtualBox-4.3.0.tar
dda81aea75a83b1489662c6bcd0677e4 /home/leoks/Downloads/VirtualBox-4.3.0.tar
[leoks#home ~]$
I run my java webserver on port 6799
My directory has a txt.txt file and pdf.pdf file
When I give localhost:6799/txt.txt, it gives perfect output saying
GET /txt.txt HTTP/1.1HTTP/1.0 200 OK
Content-type: text/plain
This is a very simple text file
But when I give localhost:6799/pdf.pdf from browser, it gives java.lang.NullPointerException
This is my code
import java.net.*;
public final class WebServer {
public static void main(String args[]) throws Exception {
int port = 6799;
System.out.println("\nListening on port " + port);
ServerSocket listen = new ServerSocket(port);
while (true) {
Socket socket = listen.accept();
HttpRequest request = new HttpRequest(socket);
Thread thread = new Thread(request);
thread.start();
}
}
}
--
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
public final class HttpRequest implements Runnable {
final String CRLF = "\r\n";
Socket socket;
public HttpRequest(Socket socket) throws Exception {
this.socket = socket;
}
#Override
public void run() {
try {
processRequest();
} catch (Exception e) {
System.out.println(e);
}
}
private void processRequest() throws Exception {
BufferedReader br;
DataOutputStream dos;
try (InputStream is = socket.getInputStream()) {
br = new BufferedReader(new InputStreamReader(is));
String requestline = br.readLine();
System.out.println("\n" + requestline);
String headerLine = null;
while ((headerLine = br.readLine()).length() != 0) {
System.out.println(headerLine);
}
dos = new DataOutputStream(socket.getOutputStream());
dos.writeBytes(requestline);
StringTokenizer tokens = new StringTokenizer(requestline);
tokens.nextToken(); // skip over the method, which should be "GET"
String fileName = tokens.nextToken();
// Prepend a "." so that file request is within the current directory.
fileName = "." + fileName;
FileInputStream fis = null;
boolean fileExists = true;
try {
fis = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
fileExists = false;
}
String statusLine = null;
String contentTypeLine = null;
String entityBody = null;
if (fileExists) {
statusLine = "HTTP/1.0 200 OK" + CRLF;
contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
} else {
statusLine = "HTTP/1.0 404 Not Found" + CRLF;
//contentTypeLine = "Content-type: " + "text/html" + CRLF;
entityBody = "<HTML>"
+ "<HEAD><TITLE>Not Found</TITLE></HEAD>"
+ "<BODY>Not Found</BODY></HTML>";
}
dos.writeBytes(statusLine);
dos.writeBytes(contentTypeLine);
dos.writeBytes(CRLF);
if (fileExists) {
sendBytes(fis, dos);
fis.close();
} else {
dos.writeBytes(entityBody);
}
}
br.close();
dos.close();
socket.close();
}
private void sendBytes(FileInputStream fis, DataOutputStream dos) throws IOException {
byte[] buffer = new byte[4096];
int bytes = 0;
while ((bytes = fis.read(buffer)) != -1) {
dos.write(buffer, 0, bytes);
}
}
private String contentType(String fileName) {
if (fileName.endsWith(".htm") || fileName.endsWith(".html")) {
return "text/html";
}
if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
return "image/jpeg";
}
if (fileName.endsWith(".gif")) {
return "image/gif";
}
if (fileName.endsWith(".txt")) {
return "text/plain";
}
if (fileName.endsWith(".pdf")) {
return "application/pdf";
}
return "application/octet-stream";
}
}
STACK TRACE
java.lang.NullPointerException
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:274)
at HttpRequest.processRequest(HttpRequest.java:65)
at HttpRequest.run(HttpRequest.java:20)
at java.lang.Thread.run(Thread.java:724)
At least one issue is this code:
while ((headerLine = br.readLine()).length() != 0) {
System.out.println(headerLine);
}
BufferedReader will return null at the end of the stream, so calling .length() on a null object will yield a NullPointerException.
A more idiomatic way to write this is:
while ((headerLine = br.readLine()) != null && headerLine.length() != 0) {
System.out.println(headerLine);
}
...which takes advantage of short-circuit logic to not evaluate the second condition if the result of (headerLine = br.readLine()) is null.
It is happening because for some reason you have toggled comment on the following line:
//contentTypeLine = "Content-type: " + "text/html" + CRLF;
Untoggle it and you're good!