In my scenario, I'm using an external read only db zipped in Assets and extracting/copying to internal storage on initial run.
The issue happens when user's device does not have sufficient memory on disk to complete the copy.
I do check for available space prior, however Android OS itself will use virtual memory/page file when low on Ram so # of free MB's is not constant.
I would like to find a way to check if file itself is complete, any way to accomplish this?
Checking that the files are consistent is always done by checking the MD5 hash of the two file if they match each other.
You can use this class from the CyanogenMod ROM repository on github.This should work pretty well https://github.com/CyanogenMod/android_packages_apps_CMUpdater/blob/cm-10.2/src/com/cyanogenmod/updater/utils/MD5.java
/*
* Copyright (C) 2012 The CyanogenMod Project
*
* * Licensed under the GNU GPLv2 license
*
* The text of the license can be found in the LICENSE file
* or at https://www.gnu.org/licenses/gpl-2.0.txt
*/
package com.cyanogenmod.updater.utils;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5 {
private static final String TAG = "MD5";
public static boolean checkMD5(String md5, File updateFile) {
if (TextUtils.isEmpty(md5) || updateFile == null) {
Log.e(TAG, "MD5 string empty or updateFile null");
return false;
}
String calculatedDigest = calculateMD5(updateFile);
if (calculatedDigest == null) {
Log.e(TAG, "calculatedDigest null");
return false;
}
Log.v(TAG, "Calculated digest: " + calculatedDigest);
Log.v(TAG, "Provided digest: " + md5);
return calculatedDigest.equalsIgnoreCase(md5);
}
public static String calculateMD5(File updateFile) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Exception while getting digest", e);
return null;
}
InputStream is;
try {
is = new FileInputStream(updateFile);
} catch (FileNotFoundException e) {
Log.e(TAG, "Exception while getting FileInputStream", e);
return null;
}
byte[] buffer = new byte[8192];
int read;
try {
while ((read = is.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String output = bigInt.toString(16);
// Fill to 32 chars
output = String.format("%32s", output).replace(' ', '0');
return output;
} catch (IOException e) {
throw new RuntimeException("Unable to process file for MD5", e);
} finally {
try {
is.close();
} catch (IOException e) {
Log.e(TAG, "Exception on closing MD5 input stream", e);
}
}
}
}
You should precalculate your md5 hash of the file and just check if it matches with the new transfered file.
Related
I have a base64 string which when decoded online using this website gives a zip file. When the zip file is downloaded it is password protected.
In my case, I know the password but I am not able to convert base64 to a zip file and also open it and read it in Android.
I used this answer on stack overflow but I am getting an error
Error: "java.util.zip.ZipException: Not in GZIP format"
I need a solution where I have the base64 String that it should decode into a zip file and then read the content of this zip file using the given password which has XML data.
Here is the code I have used so far:
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() throws Base64DecodingException {
String encoded = "PUT BASE 64ENCODED GZIPPED STRING HERE";
byte[] compressed = Base64.decode(encoded);
String data = new String(compressed);
//System.out.println(data);AAAA";
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));
}
}
Please help!
How to transfer a file(unknown extension ie maybe a pdf/word/jpeg) from PC to Android Phone using Socket Programming. The Android Phone should be able to detect the type of file transfer and should be able to open it thereafter. Also the file should go into a specific folder named after app name in External storage.
I have tried following solution. However in this case, when I select the file to be transferred, the file transferred at Android side is of arbitrary size and not of the same size as of file selected, it is of some random size. Also the file transferred cannot be opened as it does not have a fixed extension.
Any help would be appreciated.
Android code(To receive file)
package minor.subham.com.pccontrol;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Environment;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.net.*;
import java.io.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class getFile extends ActionBarActivity {
ImageView getFile;
public final static int SOCKET_PORT = Constants.SERVER_PORT; // you may change this
public final static String SERVER = Constants.SERVER_IP; // localhost
public final static int FILE_SIZE = 6022386; // file size temporary hard coded
// should bigger than the file to be downloaded
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_get_file);
getFile = (ImageView) findViewById(R.id.getFile);
getFile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Thread thread = new Thread() {
#Override
public void run() {
while(true) {
int bytesRead;
int current = 0;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
Socket sock = null;
final File file;
file = new File(Environment.getExternalStorageDirectory(), "PcControl");
try {
sock = new Socket(SERVER, SOCKET_PORT);
System.out.println("Connecting...");
// receive file
byte [] mybytearray = new byte [FILE_SIZE];
InputStream is = sock.getInputStream();
// fos = new FileOutputStream(FILE_TO_RECEIVED);
try {
fos = new FileOutputStream(file);
} catch (IOException e) {
e.printStackTrace();
}
bos = new BufferedOutputStream(fos);
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead =
is.read(mybytearray, current, (mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bos.write(mybytearray, 0 , current);
bos.flush();
fos.write(mybytearray);
fos.close();
System.out.println("File "
+ " downloaded (" + current + " bytes read)");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bos != null) try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
if (sock != null) try {
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
thread.start();
}
});
}
}
And Her is the Java Code to send file. Suppose I want to send file temp.jpg
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class send {
public final static int SOCKET_PORT = 8991; // you may change this
public final static String FILE_TO_SEND = "temp.jpg"; // you may change this
public static void main (String [] args ) throws IOException {
FileInputStream fis = null;
BufferedInputStream bis = null;
OutputStream os = null;
ServerSocket servsock = null;
Socket sock = null;
try {
servsock = new ServerSocket(SOCKET_PORT);
// while (true) {
System.out.println("Waiting...");
try {
sock = servsock.accept();
System.out.println("Accepted connection : " + sock);
// send file
File myFile = new File (FILE_TO_SEND);
byte [] mybytearray = new byte [(int)myFile.length()];
fis = new FileInputStream(myFile);
bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
os = sock.getOutputStream();
System.out.println("Sending " + FILE_TO_SEND + "(" + mybytearray.length + " bytes)");
os.write(mybytearray,0,mybytearray.length);
os.flush();
System.out.println("Done.");
}
finally {
if (bis != null) bis.close();
if (os != null) os.close();
if (sock!=null) sock.close();
}
// }
}
finally {
if (servsock != null) servsock.close();
}
}
}
Here is my source code;
I've installed microsdsvc app on the external_SD.
szSDCardFileName = "/storage/external_SD/Android/data/com.tmnt.microsdsvc/files/AAA.DAT";
if ((fp = open(szSDCardFileName, O_RDWR|O_DIRECT|O_SYNC, S_IRWXU)) == -1) {
if ((fp = open(szSDCardFileName, O_RDWR|O_DIRECT|O_SYNC|O_CREAT, S_IRWXU)) == -1) {
return -1;
}
}
memset(g_buf, 0x00, BLOCK_LENGTH);
if (read(fp, (char *)g_buf, BLOCK_LENGTH) == ERROR) {
__android_log_print(ANDROID_LOG_INFO, "JNI", "<Err>file read error[errno=%d, handle=%d]", errno, fp);
return -1;
}
when running the code on the Lg G2 Kitkat version, open() is OK, but next read() is failed with errorno 22.
I don't know that what I mistake!!
Maybe this is the reason why...
KitKat, applications will no longer be able to create, modify, or remove files and folders on 'secondary external storage device' respectively dual-storage devices with internal flash AND a removable / external SD card.
"The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions."
http://source.android.com/devices/tech/storage/index.html
package com.example.readfilefromexternalresource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Build;
public class MainActivity extends Activity {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView)findViewById(R.id.textView);
String state = Environment.getExternalStorageState();
if (!(state.equals(Environment.MEDIA_MOUNTED))) {
Toast.makeText(this, "There is no any sd card", Toast.LENGTH_LONG).show();
} else {
BufferedReader reader = null;
try {
Toast.makeText(this, "Sd card available", Toast.LENGTH_LONG).show();
File file = Environment.getExternalStorageDirectory();
File file2 = new File(file.getAbsolutePath()+File.separator + "myText.txt");
reader = new BufferedReader(new FileReader(file2));
StringBuilder textBuilder = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
textBuilder.append(line);
textBuilder.append("\n");
}
textView.setText(textBuilder);
} catch (FileNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
if(reader != null){
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
First you need to get the state of your external sd card
then you check if there is a mounted sd card, if no sd card its found, it will do nothing(you can put error msgs here)
get its absolute path and add a separator then put the file name of the file you want to read
use a BufferedReader to read your textFile.
Use a StringBuilder to build your string, it is more efficient than simple concatinating strings
after appending your strings, always close the reader to save memory, smartphones are known to have less memory than desktop
call to toString() method of the StringBuiler to create your String which you can use
String state = Environment.getExternalStorageState();
if(!state.equals(Environment.MEDIA_MOUNTED)) {
} else {
File externalDir = Environment.getExternalStorageDirectory();
File textFile = new File(externalDir.getAbsolutePath()
+ File.separator + fileName);
BufferedReader reader
= new BufferedReader(new FileReader(textFile));
StringBuilder textBuilder = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
textBuilder.append(line);
textBuilder.append("\n");
}
reader.close();
String yourString = textBuilder.toString();
}
it throws a FileNotFound exception btw. You can do the same in writing a file.
Im trying to create a Bitmap from a Png file stored on the SD card and then set that Bitmap in an imageView.
But its not working.
Here's the code:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import com.pxr.tutorial.xmltest.R;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.widget.ImageView;
public class Getbackground {
URL url;
public static long downloadFile(URL url2) {
try {
URL url = new URL ("http://oranjelan.nl/oranjelan-bg.png");
InputStream input = url.openStream();{
try {
File fileOnSD=Environment.getExternalStorageDirectory();
String storagePath = fileOnSD.getAbsolutePath();
OutputStream output = new FileOutputStream (storagePath + "/oranjelanbg.png");
try {
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
output.write(buffer, 0, bytesRead);
}
} finally {
output.flush();
output.close();
//----------------------------------------------------------------------------------------------------------
Bitmap BckGrnd = BitmapFactory.decodeFile(storagePath + "/oranjelanbg.png");
ImageView BackGround=(ImageView)findViewById(R.id.imageView1);
BackGround.setImageBitmap(BckGrnd);
//----------------------------------------------------------=-----------------------------------------------
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
input.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
} catch (IOException e) {
throw new RuntimeException(e);
}
return 0;
}
//-----------------------------------------------------------------------------------------
private static ImageView findViewById(int imageview1) {
// TODO Auto-generated method stub
return null;
}
//-----------------------------------------------------------------------------------------
}
The File does load on the SD card succesfully but I cant seem to get the img in the view.
You can't..
ImageView BackGround=(ImageView)findViewById(R.id.imageView1);
BackGround.setImageBitmap(BckGrnd);
How can you get the reference of ImageView in non activity class Getbackground?
You can only update UI component in MainUI Thread and if its in non Activity class then using reference (Context) of that calling activity class only.
So put this code in your Activity class after Getbackground completes.
I'm trying to save this Object, Inventory, to the internal storage. I have the saving and getting methods in the class itself. When I try and call the save method, I end up with the exception. I had the Exception message write to the Logcat, and here's what I got:
08-04 02:32:23.690: VERBOSE/alex(278): /test (Read-only file system)
The file /test is "Read-only file system", but I had allowed writing external storage in the Manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
Here's the Inventory class. The last two methods are the save and read methods.
package com.androidbook.inventoryproject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import android.util.Log;
public class Inventory implements Serializable {
private static final long serialVersionUID = 1L;
int numIngred;;
Ingredient[] ingredients;
ArrayList ingred = new ArrayList<Ingredient>();
public Inventory() {
numIngred = 0;
ingredients = new Ingredient[numIngred];
}
public int getNumIngred() {
return numIngred;
}
public String getIngredientName(int n) {
return ((Ingredient)ingred.get(n)).getName();
}
public Ingredient[] getIngredients() {
return ingredients;
}
public Ingredient getIngredient(int n) {
return (Ingredient)ingred.get(n);
}
public void addIngredient(String iname) {
numIngred++;
ingred.add(new Ingredient(iname));
}
public boolean saveInventory( Inventory inv) {
File suspend_f = new File("test");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
boolean keep = true;
try {
fos = new FileOutputStream(suspend_f);
oos = new ObjectOutputStream(fos);
oos.writeObject(inv);
}
catch (Exception e) {
keep = false;
Log.v("alex", "" + e.getMessage());
}
finally {
try {
if (oos != null) oos.close();
if (fos != null) fos.close();
if (keep == false) suspend_f.delete();
}
catch (Exception e) { /* do nothing */ }
}
return keep;
}
public Inventory getInventory() {
File suspend_f = new File("test");
Inventory inven = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
try{
fis = new FileInputStream(suspend_f);
ois = new ObjectInputStream(fis);
inven = (Inventory)ois.readObject();
}
catch (Exception e) {
String mess = e.getMessage();
}
finally {
try {
if (fis != null)
fis.close();
if (ois != null)
ois.close();
}
catch (Exception e) { }
}
return inven;
}
}
WRITE_EXTERNAL_STORAGE lets you write to the SD card, not to the filesystem root. You should try this:
File suspend_f = new File(Environment.getExternalStorageDirectory(), "test");
This verifies that the file you are using goes into a writable external folder.
EDIT: there is a bunch of other work you should do to verify that the SD card is available and writable. Read the specs to see how to make your file access robust by checking availability.