I am having a hard time figuring out how to write to and read from files on an Android device. The file will be formatted as XML and I already have parsers and data structures built that can format the XML into objects and objects into XML, but the last hurdle is reading the XML from a non-resource file (I know the data structures work because I it works when reading from a resource file) and also writing to a non-resource file. I am terrible at using tools to debug (not sure how to print a stack trace) but I know for a fact the problem is that I cannot read from or write to this files. I have no experience writing to files in Java which may be why I am having a rough time with this.
Write code:
File scoresFile = new File(getExternalFilesDir(null), "scores.xml");
if (!scoresFile.exists())
{
scoresFile.createNewFile();
}
OutputStream os = new FileOutputStream(scoresFile);
os.write(writer.toString().getBytes());
os.flush();
os.close();
Read Code:
XmlPullParserFactory xmlFac = XmlPullParserFactory.newInstance();
XmlPullParser qXML = xmlFac.newPullParser();
InputStream is = null;
File scoresFile = new File(c.getExternalFilesDir(null), "scores.xml");
if (!scoresFile.exists())
{
try {
scoresFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
is = new FileInputStream(scoresFile);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (is != null)
qXML.setInput(is,null);
else
qXML = c.getResources().getXml(R.xml.scores);
UPDATE: The last if clause in the read section always evaluates to false. So, the InputStream is null... that appears to be the root of my problem.
I would take a look at these two links: Using Internal Storage and Using External Storage
Both link to the same page, just different portions. Really, it depends on whether or not you want to save this file to the devices memory, or to an external medium (such as an SDcard).
Internal - Sandboxed, so that only your app can access it.
External - Anyone can access it.
Related
Hello I have been looking for ways to delete or rename an specific file in the internal storage of the cellphone. Specifically my targets are the files in the waze folder, that are in the root folder of the internal storage. As I said, I look for more information about this but nothing works for me, so I think that my error might be in the path i'm using. Here is my code:
TO RENAME:
file_Path = "/data/data/waze"
File from = new File(file_Path, "currentFileName");
File to = new File(file_Path, "newFilename");
from.renameTo(to); //this method returns me False
TO DELETE:
file_Path ="/data/data/waze/file"
File file = new File(file_Path);
boolean deleted = file.delete();
I try a lot of ways to do this, but this is the one I think is near to get it. So If anyone of you could point me my mistake/s I would thank you! A hug from Costa Rica!
You do not have read or write access to files on internal storage other than your own app's files. You cannot rename or delete files from another app, such as Waze.
The exception is that on rooted devices, you can ask to fork processes with superuser privileges, and those processes would have device-wide read/write access.
For completing #CommonsWare answer, you can check if the device is rooted, then do the methods or something else.
Here is an example,
Taken from : http://www.stealthcopter.com/blog/2010/01/android-requesting-root-access-in-your-app/
Process p;
try {
// Preform su to get root privledges
p = Runtime.getRuntime().exec("su");
// Attempt to write a file to a root-only
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("echo \"Do I have root?\" >/system/sd/temporary.txt\n");
// Close the terminal
os.writeBytes("exit\n");
os.flush();
try {
p.waitFor();
if (p.exitValue() != 255) {
// TODO Code to run on success
toastMessage("root");
}
else {
// TODO Code to run on unsuccessful
toastMessage("not root");
}
} catch (InterruptedException e) {
// TODO Code to run in interrupted exception
toastMessage("not root");
}
} catch (IOException e) {
// TODO Code to run in input/output exception
toastMessage("not root");
}
Or you can take a look at :
http://su.chainfire.eu/#how
https://github.com/Chainfire/libsuperuser
and also, use the following permission in your manifest too:
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
Or a good example is available on Github:
https://github.com/mtsahakis/RootChecker
Is there the unique identifier of SD card in Android API, And how to get it? How to distinguish between different SD card in my phone? I need the ID of SD card, please tell me, thanks.
Short answer is that there is no straight forward Java API in Android for that, as of now.
If you really need it, one way is to run the following commands and analyse the output (you can use terminal emulator app to test these):
mount
This will list mounted partitions, usually there will be a /mnt/sdcard and its related /dev/sdb1 in its output. You can process output and find sd-card partitions you are interested in.
blkid
This requires root access, that is, run su command first. This will print block device info, and /dev/sdb1 or so will have a UID associated with it.
You can use below method to get SD Card id
public String getSDCardUniqueId()
{
String sd_cid = null;
try {
File file = new File("/sys/block/mmcblk1");
String memBlk;
if (file.exists() && file.isDirectory()) {
memBlk = "mmcblk1";
} else {
//System.out.println("not a directory");
memBlk = "mmcblk0";
}
Process cmd = Runtime.getRuntime().exec("cat /sys/block/"+memBlk+"/device/cid");
BufferedReader br = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
sd_cid = br.readLine();
//System.out.println(sd_cid);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sd_cid;
}
I'm building hybrid applications that rely on 2-way communication between javascript in a webview and the hosting application.
Attitudes differ somewhat as in IOS the JS can send a message to swift (using WKWebView), that listens through
userContentController(userContentController: WKUserContentController,
didReceiveScriptMessage message: WKScriptMessage)
when implementing the WKScriptMessageHandler protocol,
whereas in Android the JS can actually call an Android method that has #JavascriptInterface annotation, after calling addJavascriptInterface().
Both approaches are OK for me, as I'm passing around data using JSON strings. Question is, what if I need to pass a media file, say an image or video, from the web page to the application? should I just pass a bitmap inside the json? Seems a little naive... recommendations?
edit: when passing an image from the application to the webpage I save the file to the file system and send the filename to the webview. Can it be done the other way around? Can javascript save to the hosting mobile device file system?
You have to host(in case of webapp) or store(in case of mobile app) the image and pass the image url, not exactly the image.
Almost all api that uses images bitmap also takes image url.
regards
Ashish
To answer your second question which is there are comments, use the following code.
Here the html content is your binary content:
FileWriter imageFileWriter = null;
BufferedWriter imageBufferedWriter = null;
ABOUtil.createDir(InMemoryDataStructure.FILE_PATH.getFileDirForimage());
File imageFileDir = new File(InMemoryDataStructure.FILE_PATH.getFileDirForimage());
String imageName = "/finalimage"+ filename + jpg
File mimageFile = new File(imageFileDir, imageName);
try {
imageFileWriter = new FileWriter(mimageFile, false);
imageBufferedWriter = new BufferedWriter(imageFileWriter);
StringBuilder sb = new StringBuilder();
sb.append(htmlContent);
sb.append(scriptInjectJavascript(lstimageNameValue));
imageBufferedWriter.write(sb.toString());
imageBufferedWriter.close();
return mimageFile;
}
catch (IOException e) {
MAFLogger.e("", "", e);
}
finally{
if(imageFileWriter!=null)
try {
imageFileWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
MAFLogger.e("","",e);
}
if(imageBufferedWriter!=null)
try {
imageBufferedWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
MAFLogger.e("","",e);
}
}
I am currently writing an android app that logs the accelerometer. (its a test app at the moment so i can prototype an algorithm.
To write out a list of SensorEventStore's (which is just a way of storing the data from a SensorEvent) to the SD card from a 30 minute recording, locks up the GUI for about 20 - 30 seconds while writing the file.
I am using the following code to write out the file to the SD card.
#Override
public void onMessage(Messages message, Object param[]) {
if(message == IDigest.Messages.SaveData) {
File folder = (File) param[0];
File accFileAll = new File(folder, startTime + "_all.acc");
FileWriter accFileWriterAll;
try {
accFileWriterAll = new FileWriter(accFileAll);
} catch (IOException e) {
accFileWriterAll = null;
}
for(Iterator<SensorEventStore> i=eventList.iterator(); i.hasNext();) {
SensorEventStore e = i.next();
if(accFileWriterAll != null) {
try {
accFileWriterAll.write(
String.format(
"%d,%d,%f,%f,%f\r\n",
e.timestamp,
e.accuracy,
e.values[0],
e.values[1],
e.values[2]
)
);
accFileWriterAll.flush();
} catch (IOException ex) {
}
}
}
new SingleMediaScanner(RunBuddyApplication.Context, accFileAll);
}
}
Can anyone give me any pointers to make this not lock up the UI, or not have to take the amount of time it currently takes to write out the file.
Firstly you should try to do this in the background. The AsyncTask is fairly well suited for the task.
Other than that, you should remove the flush() statement, and probperly close() your file writer. The flush causes the data to be written to disk in rather small portions, which is really slow. If you leave the filewriter to its own flushing, it will determine a buffer size on its own. When you properly close the FileWriter, the remaining data should be written to disk as well.
Also, you could take a look at "Try with resources" for your filewriter, but that is optional.
my history objects only have 2 fields (id + name). i have to save them. i used sharedpreferences because this is just perfect to save key-value pairs. problem is..there is no possibilty to change to location where the files are saved. i dont want to save them into the sharedpref folder because i want to give the user of the app the possibility to delete all history entries. i have to check which files are history files and which files are preferences files used by the app. this is no proble..but dirty imo. on the other hand..my history files shouldnt be in sharedpref folder..they have nothing to do in that folder..
the other possibility is to store the data in internal storage as xml for example. i would have to write a serializer and parser.
the third possibility (i just remembered writing this question)is to save it via Java Properties. this is probably the easiest solution. its like sharedpref
the last possibility is to store it in sqlite. i dont know..my data is so tiny..and i use a databae to store it?
my question is simply..what do u recommend to use and why. what do you use? same question belongs to the autocomplete values. id like to save the values the user once entered in a textfield. where to save them? where do you save such data?
thx in advance
You can create a separate sharedpreferences file for your history using (say) Context.getSharedPreferences("history") which will create a sharedpreferences file as follows.
/data/data/com.your.package.name/shared_prefs/history.xml
But I'm pretty sure that all sharedpreferences files will be created in /data/data/com.your.package.name/shared_prefs/. I don't think you can change the location.
I may be mis-interpreting your objective but for something like this I would just straight-up use a BufferedWriter from java.io.BufferedWriter to write a new file for each object. Likewise you can read the data with a BufferedReader. The code would look something like this:
public static void save(FileIO files){
BufferedWriter out = null;
try{
//use a writer to make a file named after the object
out = new BufferedWriter(new OutputStreamWriter(
files.writeFile(objectSomething)));
//the first line would be ID
out.write(Integer.toString(objectID));
//second line would be the name
out.write(objectName)
//Theres two possible IOexceptions,
//one for using the writer
//and one for closing the writer
} catch (IOException e) {
} finally {try {
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
In this example, I have used "objectSomething" as the string name of the file, objectID and objectName are the int and string respectively that your file contains.
to read this data, pretty straightforward:
public static void load(FileIO files) {
BufferedReader in = null;
try {
// Reads file called ObjectSomething
in = new BufferedReader(new InputStreamReader(
files.readFile(ObjectSomething)));
// Loads values from the file one line at a time
varID = Integer.parseInt(in.readLine());
varName = in.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
}
here, I've used varID and varName as local variables in this class that you would use if you needed them in your code throughout your application.