Optimising Android file writing - android

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.

Related

Android .write to .csv-file, file gets created but no text is saved

I have an android application that collects data from a sensor via Bluetooth.
When trying to save the data to a .csv-file on the device, the data.csv-file gets created but no text is saved in the file.
The function in question:
private void writeData(boolean writeError) {
try {
File traceFile = new File(Environment.getExternalStorageDirectory(), writeError ? "error.csv" : "data.csv");
if (!traceFile.exists())
traceFile.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(traceFile, true /*append*/));
writer.write("Test string");
} catch (Exception e) {
e.printStackTrace();
}
}
No error is thrown and I've made sure that each part of the code gets executed. Any ideas as to why this doesn't work?
Solution by Hurundi V. Bakshi
Added
writer.flush();
after
writer.write("Test string");
Documentation on flush():
Flushes this writer. Implementations of this method should ensure that all buffered characters are written to the target.

Android File Logging

I'm planning to implement a logging mechanism for security-related messages in Android. I want to be able to use it in the Android source code like the Log class, e.g. SecuLog.log(String msg);
It shall in the following ways differ from the normal Log
No levels like DEBUG, INFO, etc...
Output should directly go into a File on the device. There must not be the need of redirecting Logcat output for example.
As multiple processes shall be able to log security-related messages I failed with just implementing a LoggingClass in com.android.util with a static PrintWriter.
static {
try {
writer = new PrintWriter("data/secu.log");
} catch (FileNotFoundException e) {
Log.e(TAG, "Exception initializing SecuLog.", e);
}
}
This did not work, because Android is designed to run multiple dalvik-VMs that all try to access the given file. So i need some kind of non-blocking File I/O.
Is there a way to reuse any logging mechanism from Android without the need to explicitly redirect logcat output?
How else can I achieve a simple file logging mechanism, that can be called from every other process? Should I implement a logging Service? Does this service has to be a bound service or a started service? Do I have to use AIDL?
After following the comments to my question I chose the following solution:
created multiple log files
one file for each process
used processId as suffix for log files
designed a log viewing app, that puts all logs togheter
For my logging class I used the following code:
static {
try {
File file = new File("data/secu" + android.os.Process.myPid() + ".log");
file.createNewFile();
file.setReadable(true, false);
file.setExecutable(true, false);
writer = new PrintWriter(file);
} catch (IOException e) {
Log.e(TAG, "Exception initializing SecuLog.", e);
}
}
This post is quite old by now. But I recently did this work and want to share it.
Suggestions are welcome.
Multiple libs are available for this purpose, but if you want to do it yourself, here you go.
fun log(tag: String?, message: String) {
try {
val direct = File("${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/$DIRECTORY_NAME")
if (!direct.exists()) {
direct.mkdir()
}
val fileNameTimeStamp = "${SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())}"
val logTimeStamp = SimpleDateFormat("E MMM dd yyyy 'at' hh:mm:ss:SSS aaa", Locale.getDefault()).format(Date())
val fileName = "$fileNameTimeStamp.html"
val file = File("${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/$DIRECTORY_NAME" + File.separator + fileName)
file.createNewFile()
if (file.exists()) {
val fileOutputStream = FileOutputStream(file, true)
//Here I have added a html tag to beautify/highlight the output in file.
fileOutputStream.write("<p style=\"background:lightgray;\"><strong style=\"background:lightblue;\">&nbsp&nbsp$logTimeStamp :&nbsp&nbsp</strong>&nbsp&nbsp$message</p>".toByteArray())
fileOutputStream.close()
}
} catch (e: Exception) {
Log.e(TAG, "Error while logging into file : $e")
}
}
The purpose of keeping it html file is to open it browser and could highlight different items. Becuase log searching and debugging is very boring and beautifying could reduce the mental stress.
Output file looks like:

File data storing

i did an application to collects light sensor data, such that these data are stored in text file in the external sdcard, the data is stored correctly and file are created successfully but the problem is when then application running on the my device for x period (e.g 1 min)the data is stored but when is close the application and re running it on from the device for the same period also the new collected data are append stored to the previous stored data from previous running and i noted that when the sizes of the text files is increases with each running.
i need for each running ,the collected data is stored totally (for the whole period of the running i.e 1 min ) in the text file and when i re- running the application again the new collected data of the new running to be overwriting on previous stored data.
i attempted to do that using arraylist, i .e when then app starts running i put all gathered reading in array list and when the running is stopped the arraylist will out all gathered data to the text file but when i re-running app the array list also gathered data and append out it into the text file next to the previous running stored data, where this is the problem which need to solve,i need to overwrite new running gathered data on the previous running stored data.
the code of collecting light sensor data looks like:
#Override
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType()==Sensor.TYPE_LIGHT){
max = msensorManager.getDefaultSensor(Sensor.TYPE_LIGHT).getMaximumRange();
//getMaximumRange() is the maximum range of the sensor in the sensor's unit.
//tv1.setText("Max Reading: " + String.valueOf(max));
tv1.setText(msg +"Max Reading: " + String.valueOf(max) );
tv1.invalidate();
lightMeter.setMax((int)max);
//setMax is the max of the upper range of this progress bar
currentReading = event.values[0];
//timestamp = event.timestamp;
lightMeter.setProgress((int)currentReading);
Toast.makeText(MainActivity.this,"Event Happend '", Toast.LENGTH_SHORT).show();
tv2.setText("Current Reading: " + String.valueOf(currentReading));
current_reading_list.add((double) currentReading);
}
the code of writing from array list into file looks like :
public void writing_in_file_1(){
try{
fw = new FileWriter(file_1, true);
bw = new BufferedWriter(fw);
out = new PrintWriter(bw);
//out.append( String.valueOf(currentReading + " \t"));
//out.append(String.valueOf(current_reading_list));
out.print(String.valueOf(current_reading_list));
out.flush();
Toast.makeText(this,"Done writing SD 'specific text file'", Toast.LENGTH_SHORT).show();
}
catch (IOException e)
{
e.printStackTrace();
}
finally{
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
the writing is done when the stop button is pressed:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1:
counter_function();
//onResume();
break;
case R.id.bt2:
onPause();
writing_in_file_1();
tv1.setText("");
tv2.setText("");
break;
default:
break;
}
}
can any one help me?
thank you in advance.
You are using the constructor FileWriter(File file, boolean append) with append = true
Replace
fw = new FileWriter(file_1, true);
with
fw = new FileWriter(file_1, false);

Android take screenshot on rooted device

UPDATE There are a number of other posts asking how to get a Screenshot in android but none seemed to have a full answer of how to do so. Originally I posted this as a question due to a particular issue I was running into while attempting to open a stream to the Frame Buffer. Now I've swapped over to dumping the Frame Buffer to a file so I've updated my post to show how I got there. For reference (and acknowledgement), I found the command to send the FrameBuffer to a file from this post (unfortunately he didn't provide how he got to that point). I'm just missing how to turn the raw data I pulled from the Frame Buffer into an actual image file.
My intention was to take a full dump of the actual screen on an Android Device. The only way I could find to do so without using the adb bridge was to directly access the Frame Buffer of the system. Obviously this approach will require root privileges on the device and for the app running it! Fortunately for my purposes I have control over how the Device is set up and having the device rooted with root privileges provided to my application is feasible. My testing is currently being done on an old Droid running 2.2.3.
I found my first hints of how to approach it from https://stackoverflow.com/a/6970338/1446554. After a bit more research I found another article that describes how to properly run shell commands as root. They were using it to execute a reboot, I use it to send the current frame buffer to an actual file. My current testing has only gotten as far as doing this via ADB and in a basic Activity (each being provided root). I will be doing further testing from a Service running in the background, updates to come! Here is my entire test activity that can export the current screen to a file:
public class ScreenshotterActivity extends Activity {
public static final String TAG = "ScreenShotter";
private Button _SSButton;
private PullScreenAsyncTask _Puller;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_SSButton = (Button)findViewById(R.id.main_screenshotButton);
_SSButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (_Puller != null)
return;
//TODO: Verify that external storage is available! Could always use internal instead...
_Puller = new PullScreenAsyncTask();
_Puller.execute((Void[])null);
}
});
}
private void runSuShellCommand(String cmd) {
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
StringBuilder sbstdOut = new StringBuilder();
StringBuilder sbstdErr = new StringBuilder();
try { // Run Script
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(cmd);
osw.flush();
osw.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
if (proc != null)
proc.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
sbstdOut.append(readBufferedReader(new InputStreamReader(proc.getInputStream())));
sbstdErr.append(readBufferedReader(new InputStreamReader(proc.getErrorStream())));
}
private String readBufferedReader(InputStreamReader input) {
BufferedReader reader = new BufferedReader(input);
StringBuilder found = new StringBuilder();
String currLine = null;
String sep = System.getProperty("line.separator");
try {
// Read it all in, line by line.
while ((currLine = reader.readLine()) != null) {
found.append(currLine);
found.append(sep);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
class PullScreenAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
File ssDir = new File(Environment.getExternalStorageDirectory(), "/screenshots");
if (ssDir.exists() == false) {
Log.i(TAG, "Screenshot directory doesn't already exist, creating...");
if (ssDir.mkdirs() == false) {
//TODO: We're kinda screwed... what can be done?
Log.w(TAG, "Failed to create directory structure necessary to work with screenshots!");
return null;
}
}
File ss = new File(ssDir, "ss.raw");
if (ss.exists() == true) {
ss.delete();
Log.i(TAG, "Deleted old Screenshot file.");
}
String cmd = "/system/bin/cat /dev/graphics/fb0 > "+ ss.getAbsolutePath();
runSuShellCommand(cmd);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
_Puller = null;
}
}
}
This also requires adding the android.permission.WRITE_EXTERNAL_STORAGE permission to the Manifest. As suggested in this post. Otherwise it runs, doesn't complain, doesn't create the directories nor the file.
Originally I couldn't get usable data from the Frame Buffer due to not understanding how to properly run shell commands. Now that I've swapped to using the streams for executing commands I can use '>' to send the Frame Buffer's current data to an actual file...
Programmatically you can run "adb shell /system/bin/screencap -p /sdcard/img.png" as below :
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
An easy solution for ICS devices is to use the following from the command line
adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png
This'll save the screenshot.png file in the current directory.
Tested on a Samsung Galaxy SII running 4.0.3.
That would be different for different phones. It depends on the underlying graphics format of your device. You can poll what the graphics format is using system calls. If you are only going to run this on devices that you know the graphics format of you can write a converter that turns it into a known format.
You can have a look at the following project: http://code.google.com/p/android-fb2png/
If you look at the source code for fb2png.c you can see that they poll FBIOGET_VSCREENINFO which contains info about how the device stores the screen image in memory. Once you know that, you should be able to convert it into a format you can use.
I hope this helps.

Writing to and Reading from a file in Android

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.

Categories

Resources