I'm doing a simple app in Android and in a certain part of the app I would like to create an Excel file and write in it. I've already prepared everything to use jexcel library to edit an excel using Java, but the thing is I can't find the Excel file I created. I've tried to find it in my own device executing the app, but I couldn't.
String fileName = "hours.xls";
File file = new File(getApplicationContext().getFilesDir() + fileName);
Can anybody help me please?
Thanks in advance :)
On Android KitKat, it returns /data/data/{your package name}/files, however I imagine this could change depending on your platform version. Thus if you're just trying to dig through your filesystem and see a file, it's safe to use this path, but if you're using this path for some functionality across multiple platform versions, you should only reference it using getFilesDir().
What are you planning on using this file for? Do you want it usable by other apps too? Using getApplicationContext().getFilesDir() will give you /data/data/com.package/files but if you want a file that's easily accessible by yourself and other apps, you're better off using something like getExternalFilesDir()
If you want to access your file via your PC (with an usb cable) or via a file manager on your device, prefer:
new File(getExternalFilesDir(null), fileName);
This folder is created in .../Android/data/ ... com.yoursociety.yourapp/files ...
null means that you do not want to store files in predefined folders like Movies, Pictures and so on.
(See documentation for more info)
This worked:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
b = (Brain)load("brain.txt");
if (b == null) {
b = new Brain();
}
vocabulary = (ArrayList <String>) load("vocabulary.txt");
if (vocabulary == null) {
vocabulary = new ArrayList <String> ();
vocabulary.add("I love you.");
vocabulary.add("Hi!");
}
b.setRunning(true);
}
public Object load(String fileName) {
File file = new File("/storage/emulated/0/Android/data/com.cobalttechnology.myfirstapplication/files/" + fileName);
if (!file.exists()) {
return null;
}
try {
Object o;
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
o = ois.readObject();
if (o == null) {
System.out.println(fileName + " = null");
}
ois.close();
fis.close();
System.out.println("Loaded: " + fileName);
return o;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return null;
}
public void save(Object o, String fileName) {
File file = new File("/storage/emulated/0/Android/data/com.cobalttechnology.myfirstapplication/files/" + fileName);
try {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(o);
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Read the documentation, this method reads the files stored in the internal storage that were created with
with openFileOutput():
getFilesDir()
Returns the absolute path to the directory on the filesystem where
files created with openFileOutput(String, int) are stored.
Related
I have a very specific issue - I am trying to write to external storage on an Asus Nexus 7, but it is writing to the emulated directory on the device.
Here is the code I am using:
public static void writeExternalMedia(Context context) {
if(isExternalStorageWritable()) {
String content = "hello world";
File filedir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/test");
filedir.mkdir();
File file;
FileOutputStream outputStream;
try {
file = new File(filedir, "test.txt");
if (!file.exists()) {
file.createNewFile();
}
outputStream = new FileOutputStream(file);
outputStream.write(content.getBytes());
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Whenever I restart the device, the directories appear under the device when plugged in, which is what I would expect to happen when the function above gets executed.
I have tried searching for a solution and cannot find the answer to my question.
I made two methods. One for creating a file and one for appending to it. I think the issue is that you're not calling createNewFile.
private File CreateFile(String fileName)
{
File file = new File(this.getFilesDir(), fileName);
try
{
if(!file.exists())
{
file.createNewFile();
}
}
catch (IOException e)
{
e.printStackTrace();
}
return file;
}
private void appendToFile(String file, String content)
{
try
{
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(this.openFileOutput(file, this.MODE_APPEND));
outputStreamWriter.append(content + "\n");
outputStreamWriter.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
Alright after much searching and testing I finally came across a solution, linked via one of the other answers.
https://stackoverflow.com/a/28448843/979220
The solution was to scan the media files, which causes the files to propagate to the external storage, rather than staying in the emulated storage.
My application should work not only in online but also in offline mode. For that reason I am considering find the best way for cashing data. I't like use SharedPreference for store data but in android documentation writen Maximum size in characters allowed for a preferences value is 8192. I don't know this is ok or not? I tried to pass out of this idea trying to use FileCashing or sqLite cashing.
So what you think guys what is the best SharedPreference vs FileCashing or vs SqLiteCaching?
Save the json in cache directory as file....
Save:
// Instantiate a JSON object from the request response
JSONObject jsonObject = new JSONObject(json);
// Save the JSONOvject
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDir(),"")+"cacheFile.srl"));
out.writeObject( jsonObject );
out.close();
Retrieve:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
I personally like to do this the following way. Create a SQLite database that can hold your content. Then, bind the user interface directly to the database using Adapters & Content Providers that send a notification whenever the data is changed so that the UI can update itself. The last piece in the equation is some form of synchronization service that downloads content and saves it to the database asynchronously. That way, you can manage your data very easily because it is all in the same place. The only part you'll have to figure out for your app is how you decide when to update or remove the data from the database.
Adapters
ContentProvider
Synchronization
Based on your requirement I would recommend SQLite data base.
Since shared preference is suitable for configuration storage - often small data/strings.
File cache is hard to manage, so I recommend SQLite - easy to manage and ability to store mass data.
Considering the performance, if the number of index is not that huge, SQLite database should have the acceptable performance. E.g. only several ms slower than a file cache.
You might be able to combine these two approaches together. Use random access file with index-offset stored in SQLite.
I have used Internal Storage which store file in Application package directory that can't be accessible by not rooted device.
Here the class which can create, read and delete the file
public class ReadWriteJsonFileUtils {
Activity activity;
Context context;
public ReadWriteJsonFileUtils(Context context) {
this.context = context;
}
public void createJsonFileData(String filename, String mJsonResponse) {
try {
File checkFile = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
if (!checkFile.exists()) {
checkFile.mkdir();
}
FileWriter file = new FileWriter(checkFile.getAbsolutePath() + "/" + filename);
file.write(mJsonResponse);
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readJsonFileData(String filename) {
try {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + filename);
if (!f.exists()) {
onNoResult();
return null;
}
FileInputStream is = new FileInputStream(f);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
onNoResult();
return null;
}
public void deleteFile() {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
File[] files = f.listFiles();
for (File fInDir : files) {
fInDir.delete();
}
}
public void deleteFile(String fileName) {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + fileName);
if (f.exists()) {
f.delete();
}
}
}
You can create, read and delete the file by calling ReadWriteJsonFileUtils class methods as follows:
For creating file:
try {
new ReadWriteJsonFileUtils(context).createJsonFileData(file_name, data);
} catch (Exception e) {
e.printStackTrace();
}
For reading file:
String jsonString = new ReadWriteJsonFileUtils(context).readJsonFileData(file_name);
For deleting single file
new ReadWriteJsonFileUtils(context).deleteFile(file_name);
For deleting all file
new ReadWriteJsonFileUtils(context).deleteFile();
saving socres to highscore.sav file, it works fine on desktop, but not on android. why?
String fileName = "highScores.sav";
file = new File(fileName);
public static void save(){
try{
FileOutputStream fileOut = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(gd);
out.close();
}
catch(Exception e){
e.printStackTrace();
System.out.println(e);
Gdx.app.exit();
}
}
public static void load(){
try{
if(!saveFileExists()){
init();
return;
}
FileInputStream fileIn = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fileIn);
gd = (GameData) in.readObject();
in.close();
}
catch(Exception e){
e.printStackTrace();
System.out.println(e);
Gdx.app.exit();
}
}
got error: java.io.FileNotFoundException: /highScores.sav: open failed: EROFS (Read-only file system)
This isn't working because you have not specified a directory to save into. Android has tight restrictions on where an app can write files.
You don't need any permissions to read or write a file to internal memory. But you do need to specify internal memory (called local memory in libgdx).
Libgdx already handles this directly for you so you don't need to differentiate between desktop and Android. This explains exactly how to do it. All you need is the string or bytes you want to write into the file, and the libgdx API's handle the rest.
FileHandle file = Gdx.files.local(filename);
file.writeString(stringToWrite, false);
If you want to continue using your method of writing the file, you can get the path to the file like this:
String fileName = "highScores.sav";
file = new File(Gdx.files.getLocalStoragePath () + "/" + fileName);
Have you added the permission to the android app to allow writing to the storage space?
My application should work not only in online but also in offline mode. For that reason I am considering find the best way for cashing data. I't like use SharedPreference for store data but in android documentation writen Maximum size in characters allowed for a preferences value is 8192. I don't know this is ok or not? I tried to pass out of this idea trying to use FileCashing or sqLite cashing.
So what you think guys what is the best SharedPreference vs FileCashing or vs SqLiteCaching?
Save the json in cache directory as file....
Save:
// Instantiate a JSON object from the request response
JSONObject jsonObject = new JSONObject(json);
// Save the JSONOvject
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDir(),"")+"cacheFile.srl"));
out.writeObject( jsonObject );
out.close();
Retrieve:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
I personally like to do this the following way. Create a SQLite database that can hold your content. Then, bind the user interface directly to the database using Adapters & Content Providers that send a notification whenever the data is changed so that the UI can update itself. The last piece in the equation is some form of synchronization service that downloads content and saves it to the database asynchronously. That way, you can manage your data very easily because it is all in the same place. The only part you'll have to figure out for your app is how you decide when to update or remove the data from the database.
Adapters
ContentProvider
Synchronization
Based on your requirement I would recommend SQLite data base.
Since shared preference is suitable for configuration storage - often small data/strings.
File cache is hard to manage, so I recommend SQLite - easy to manage and ability to store mass data.
Considering the performance, if the number of index is not that huge, SQLite database should have the acceptable performance. E.g. only several ms slower than a file cache.
You might be able to combine these two approaches together. Use random access file with index-offset stored in SQLite.
I have used Internal Storage which store file in Application package directory that can't be accessible by not rooted device.
Here the class which can create, read and delete the file
public class ReadWriteJsonFileUtils {
Activity activity;
Context context;
public ReadWriteJsonFileUtils(Context context) {
this.context = context;
}
public void createJsonFileData(String filename, String mJsonResponse) {
try {
File checkFile = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
if (!checkFile.exists()) {
checkFile.mkdir();
}
FileWriter file = new FileWriter(checkFile.getAbsolutePath() + "/" + filename);
file.write(mJsonResponse);
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readJsonFileData(String filename) {
try {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + filename);
if (!f.exists()) {
onNoResult();
return null;
}
FileInputStream is = new FileInputStream(f);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
onNoResult();
return null;
}
public void deleteFile() {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
File[] files = f.listFiles();
for (File fInDir : files) {
fInDir.delete();
}
}
public void deleteFile(String fileName) {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + fileName);
if (f.exists()) {
f.delete();
}
}
}
You can create, read and delete the file by calling ReadWriteJsonFileUtils class methods as follows:
For creating file:
try {
new ReadWriteJsonFileUtils(context).createJsonFileData(file_name, data);
} catch (Exception e) {
e.printStackTrace();
}
For reading file:
String jsonString = new ReadWriteJsonFileUtils(context).readJsonFileData(file_name);
For deleting single file
new ReadWriteJsonFileUtils(context).deleteFile(file_name);
For deleting all file
new ReadWriteJsonFileUtils(context).deleteFile();
Greetings and a happy new year to all my fellow programmers.
My code downloads an apk file from a remote server. I need to initiate the installation procedure through code, without user having to explicitly install it. The catch is that i cannot use an SD card download the apk file.
I can navigate to the data/data/files folder and can see my file downloaded. The only problem is that i cannot get it installed. This is what i get
'/data/data/org.obs.testinstall.main/files/app.apk': Permission denied
I understand that Android does not give permission to access the data directory.
My question is how can i download and install an application(apk) without using a SD card. This application is not intended to be published in the market. I have tried using both the Internal Storage using
FileOutputStream fos = openFileOutput("app.apk", Context.MODE_PRIVATE);
and the cache directory
File file = getCacheDir();
File outputFile = new File(file, "app.apk");
Both give the same result .. "Permission denied"
When i change the code to incorporate an SD card the application works perfectly, but using an SD card is not an option.
Surely there must be a way to do this. It is hard to believe that such a handicap exist in the Android O/S.
Has anybody done this? Any workarounds? Any pointers would be helpful.
It it caused by android application can not read from
another application file if it is written using PRIVATE mode.
You can do this:
String fileName = "tmp.apk";
FileOutputStream fos = openFileOutput(fileName,
MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
// write the .apk content here ... flush() and close()
// Now start the standard instalation window
File fileLocation = new File(context.getFilesDir(), fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(fileLocation),
"application/vnd.android.package-archive");
context.startActivity(intent);
Be careful though, because that file is now world-visible,
and can be seen by any application in the same device,
if they know the file location.
No need to root.
You can just use linux command chmod to do it.
public static String exec(String[] args) {
String result = "";
ProcessBuilder processBuilder = new ProcessBuilder(args);
Process process = null;
InputStream errIs = null;
InputStream inIs = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read = -1;
process = processBuilder.start();
errIs = process.getErrorStream();
while ((read = errIs.read()) != -1) {
baos.write(read);
}
baos.write('\n');
inIs = process.getInputStream();
while ((read = inIs.read()) != -1) {
baos.write(read);
}
byte[] data = baos.toByteArray();
result = new String(data);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (errIs != null) {
errIs.close();
}
if (inIs != null) {
inIs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
return result;
}
in your program,it can be invoked like this:
String[] args1 = { "chmod", "705", "/data/data/org.obs.testinstall.main/files/" };
exec(args1);
String[] args2 = { "chmod", "604", "/data/data/org.obs.testinstall.main/files/app.apk" };
exec(args2);
Then you can install the app.apk as wished.
Also you can use
downloadedFile.setReadable(true, false);
with
fileOutputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
There are two setReadable method. The first has one parameter and the second one has two parameters.
setReadable(boolean readable)
setReadable(boolean readable, boolean ownerOnly)
Try rooting your device and then running the program from the device, instead of using an emulator.
For me I deleted the apk file right after the startActivity, which is asynchronous.
Too bad there is no better description of the parsing error (file not found, access denied, corrupted file in package,...)
when you send intent to install apk, you can use this function to change mode for apk directory.
private static boolean changeMode(String filePath, String prefixPath) {
if (TextUtils.isEmpty(prefixPath) || !filePath.startsWith(prefixPath)) {
return true;
}
try {
String[] args1 = { "chmod", "705", prefixPath};
Runtime.getRuntime().exec(args1);
} catch (IOException e) {
e.printStackTrace();
return false;
}
String subPath = filePath.split(prefixPath)[1];
String[] subArr = subPath.split(File.separator);
for (String path : subArr) {
if (!TextUtils.isEmpty(path)) {
prefixPath = prefixPath + File.separator + path;
try {
if (!prefixPath.endsWith(".apk")) {
String[] progArray1 = {"chmod", "705", prefixPath};
Runtime.getRuntime().exec(progArray1);
} else {
String[] progArray2 = {"chmod", "604", prefixPath};
Runtime.getRuntime().exec(progArray2);
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
return true;
}
And before you send intent, check chmod is it alreay success.
boolean chmodRes = changeMode(filePath, context.getCacheDir().getAbsolutePath())
&& changeMode(filePath, context.getFilesDir().getAbsolutePath());
if (!chmodRes) {
return false;
}