I am read & write username & password to android device using my application to internal storage. I am successful writing to the device, but while reading I get error. On start of the aplication I read that file and I get "The applicaton (...) has stopped unexpectedly. Please try again." with "Force Close" button and the app closes. I tried different ways to read, but all showed same results. I write my data as username + "\n" + passwrd + "\n". This is the code for reading data :
private static String ReadFromFile(String fileName) {
String text = "";
FileInputStream fis = null;
byte[] fileData;
try {
StringBuffer sb = new StringBuffer();
int c = 0;
fis = AppContext.openFileInput(fileName);
if (fis.available() != 0) {
fileData = new byte[fis.available()];
c = fis.read(fileData);
Log.i(TAG, "Read Byes = " + c );
java.util.StringTokenizer stk = new java.util.StringTokenizer(new String(fileData), "\n");
text = stk.toString();
} else
throw new IOException("fis.available() <= 0"); /*
c = (char)fis.read();
while (c != -1){
if (c != -1)
sb.append(c);
c = (char)fis.read();
}
text = sb.toString();
*/
fis.close();
} catch (FileNotFoundException e) {
text = "null " + e.getMessage();
} catch (IOException e) {
text = "null " + e.getMessage();
} finally {
fis = null;
}
return text;
}
/*
try {
StringBuffer sb = new StringBuffer();
RandomAccessFile raf = new RandomAccessFile(ENC_LOGIN_FILE, "r");
while ((str1 = raf.readLine()) != null){
sb.append(str1);
}
str1 = sb.toString();
} catch (FileNotFoundException e) {
errorMessage = "File Not Found: " + e.getMessage();
//e.printStackTrace();
} catch (IOException ioe) {
errorMessage = "IOExcp: " + ioe.getMessage();
//e.printStackTrace();
}*/
No path is used and the filename directly is given to write & read file. I checked out Problem facing in reading file from Internal memory of android from where I tried StringTokenizer.
Can anyone help me know where am I going wrong. The following permission are set :
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"></uses-permission>
<uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"></uses-permission>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"></uses-permission>
<uses-permission android:name="android.permission.READ_SYNC_STATS"></uses-permission>
<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>
Also how do I debug the application. How to check the data written in Log. If I use SOP, where does it dispaly - it doesn't display in Console window ? Please help me, I am n newbie in android development.
One more thing to clarify : My motto is to store username and password in such a way that user must not be able to read them directly. I have already used MODE_PRIMITIVE. Is their a need to use JSONObject to save this data. I had a look at JSON in couple of sites & API but couldn't make out why and where it should be used. Using MODE_PRIMITIVE I believe even the user can't read the file. Only my application can read it. Then I don't think I should use JSON. Please correct me if I am wrong.
Any help is highly appreciated.
Thanks.
A suggestion:
If you are only saving username and password then use SharedPreferences instead of saving the data in a file. It is a much secure way and plus very hassle free.
Use this blog article on How to use Shared Preferences:
http://saigeethamn.blogspot.com/2009/10/shared-preferences-android-developer.html
fis = AppContext.openFileInput(fileName);
fileData = new byte[fis.available()];
java.util.StringTokenizer stk =
new java.util.StringTokenizer(new String(fileData), "\n");
It appears to me that you're trying to create a new String using an uninitialized array as input. You've asked for the array to be a specific size, but you haven't done anything to read data into the array. (Note that available() only asks for the size of the data that can be read without blocking; it doesn't actually read the data. For that you need the read() method.)
Try this:
fis = AppContext.openFileInput(fileName);
fileData = new byte[fis.available()];
fis.read(fileData);
java.util.StringTokenizer stk =
new java.util.StringTokenizer(new String(fileData), "\n");
You should check the return value of fis.read(), but give this a try to see if it lets you progress further.
Related
I previously used external storage to store specific data that I would like to share between my applications (without having any contentprovider "host")
File folder = new File(Environment.getExternalStorageDirectory(), "FOLDER_NAME");
File file = new File(folder, "FILE_NAME.dat");
FileOutputStream outputStream = new FileOutputStream(file);
That is why I am trying to use BlobStoreManager, as suggested in google's recommendation for targeting 30 (https://developer.android.com/training/data-storage/shared/datasets)
The read & write are based on a BlobHandle with 4 parameters, one being MessageDigest based on a "content". BlobHandle must use the same 4 parameters, or read will fail (SecurityException).
I managed to write data, and to read it, but it makes no sense:
It seems that in order to write, I need to use the data I want to write to generate the BlobHandle.
Then, to read, as BlobHandle must use the same 4 parameters, I also need the data I wrote to be able to read.
Totally illogic, as I wanted to read this data, I don't have it!
I must miss something or just do not understand how it work. If someone can help :)
Here are my sample:
If I set the following:
createBlobHandle: content = "mydata"
write: data = "mydata"
Then write will success, and read will success too. But it I can not know the value before reading it in a normal usecase :(
If I set the following (which would be logic, at least to me):
createBlobHandle: content = "somekey"
write: data = "mydata"
Then write will fail :(
#RequiresApi(api = Build.VERSION_CODES.R)
private BlobHandle createBlobHandle() {
//Transfer object
String content = "SomeContentToWrite";
String label = "label123";
String tag = "test";
//Sha256 summary of the transmission object
try {
byte[] contentByte = content.getBytes("utf-8");
MessageDigest md = MessageDigest.getInstance("sha256");
byte[] contentHash = md.digest(contentByte);
return BlobHandle.createWithSha256(contentHash, label,0, tag);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
private void write() {
String data = "SomeContentToWrite";
#SuppressLint("WrongConstant") final BlobStoreManager blobStoreManager = ((BlobStoreManager) applicationContext.getSystemService(Context.BLOB_STORE_SERVICE));
//Generate the session of this operation
try {
BlobHandle blobHandle = createBlobHandle();
if (blobHandle == null)
return;
long sessionId = blobStoreManager.createSession(blobHandle);
try (BlobStoreManager.Session session = blobStoreManager.openSession(sessionId)) {
try (OutputStream pfd = new ParcelFileDescriptor.AutoCloseOutputStream(session.openWrite(0, data.getBytes().length))) {
//The abstract of the written object must be consistent with the above, otherwise it will report SecurityException
Log.d(TAG, "writeFile: >>>>>>>>>>text = " + data);
pfd.write(data.getBytes());
pfd.flush();
//Allow public access
session.allowPublicAccess();
session.commit(applicationContext.getMainExecutor(), new Consumer<Integer>() {
#Override
public void accept(Integer integer) {
//0 success 1 failure
Log.d(TAG, "accept: >>>>>>>>" + integer);
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String read() {
String data = "";
#SuppressLint("WrongConstant") final BlobStoreManager blobStoreManager = ((BlobStoreManager) applicationContext.getSystemService(Context.BLOB_STORE_SERVICE));
BlobHandle blobHandle = createBlobHandle();
if (blobHandle != null) {
try (InputStream pfd = new ParcelFileDescriptor.AutoCloseInputStream(blobStoreManager.openBlob(createBlobHandle()))) {
//Read data
byte[] buffer = new byte[pfd.available()];
pfd.read(buffer);
String text = new String(buffer, Charset.forName("UTF-8"));
Log.d(TAG, "readFile: >>>>>>>>>>>>>>>>>>>>" + text);
} catch (IOException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
return data;
}
According to the official training documentation linked in the question, the missing piece of information, at the time of the question having been asked, is that the four pieces of data contained in the BlobHandler need to be uploaded to a server owned by the client application then subsequently downloaded by which ever other application wants to access the blob via the BlobStorageManager.
So it would seem that on-device blob discovery is not supported. There could also be a solution possible using a Content Provider which could offer up the four required pieces of data, thus circumventing the need for the server infrastructure.
I just started to learn developping android and I have a (probably) basic questions, but I didn't find anything clear.
I'm trying to store data in a JSON file, well, I've understood the logic to store it, my way is:
public boolean writeFileJson(JSONObject jobj) {
try {
FileOutputStream fOut = openFileOutput(file, Context.MODE_PRIVATE);
fOut.write(jobj.toString().getBytes());
fOut.close();
Toast.makeText(getBaseContext(), "file saved", Toast.LENGTH_SHORT).show();
} catch (Exception e1) {
e1.printStackTrace();
}
return true;
}
But my problem is to read, and concretely for the first time, because the way I do it is:
public String readFileJson() {
int c;
String temp = "";
try {
FileInputStream fin = openFileInput(file);
while ((c = fin.read()) != -1) {
temp = temp + Character.toString((char) c);
}
Toast.makeText(getBaseContext(), "file read", Toast.LENGTH_SHORT).show();
} catch (Exception e2) {
}
return temp;
}
So wen I read it for the first time and I want to acces to a parameter of my JSON is obvious that any JSON Object already exist in the file.
So I try to save a first JSON Object with my parameters in onCreate() method and save it in the file, but wen I run the app, and I stop it, it returns again to execute onCreate() and deletes all data stored during the run time.
So my question is: There is any way to init only for one time the parameters of the JSON file to could access for the first time unlike it's empty???
I hope that I'd explained well!!
Thanxxxx!!!!
You can create your own flag boolean and check when you start.
Well I don't understand well why you can use a flag if the flag is set to init value in onCreate(), but I've tried a basic method: check each time if the json file is null. But it's like so basic no? Is there any ther way, or trying to understand how to use flags without reset their values?
msgjson = readFileJson();
if(msgjson == "") {
json.put("ARRAY", jsonArray);
}else{
json = new JSONObject(msgjson);
}
Thanx!!
I am trying to get the Logcat (at least last few lines) on a button click but nothing comes up -
view.findViewById(R.id.logdone).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Make file name.
String fullName = "userlogs";
// Extract to file.
File file = new File(fullName);
InputStreamReader reader = null;
FileWriter writer = null;
try
{
// get input stream
String cmd = "logcat -d -v time";
Process process = Runtime.getRuntime().exec(cmd);
reader = new InputStreamReader (process.getInputStream());
// write output stream
writer = new FileWriter (file);
char[] buffer = new char[10000];
do
{
int n = reader.read (buffer, 0, buffer.length);
if (n == -1)
break;
writer.write (buffer, 0, n);
} while (true);
reader.close();
writer.close();
}
catch (IOException e)
{
if (writer != null)
try {
writer.close();
} catch (IOException e1) {
}
if (reader != null)
try {
reader.close();
} catch (IOException e1) {
}
e.printStackTrace();
return;
}
}
}
NOTE:
I do have permissions -
<uses-permission android:name="android.permission.READ_LOGS" />
UPDATE:
My most of the content is in Log.d() then Log.v() then Log.e() then Log.i(). But how to get the last event lines on a button click. My purpose is to get those lines and send them via email to the developer.
I am using the popular third party API known as ACRA to send email which is working fine.
I can use StringBuilder to put all my device logs into it and then to send via email.
But I am unable to get.
Any elegant way that works well effectively ?
Given the comment I made about the READ_LOGS permission no longer being granted to non-system apps, I would instead recommend using a MemoryHandler with a standard Java Logger. On a button click, you can push the messages to a target StreamHandler (which you can use to just dump them into the output buffer of your choice).
Is it possible to get the last few lines of a logcat on a button click?
There has never been a documented and supported way for apps to get anything from LogCat. And, as Turix notes, things were locked down further in Android 4.2.
Any elegant way that works well effectively ?
Log the data yourself to a file that you control, rather than (or in addition to) logging the data to LogCat.
I'm trying to set up a log handler to output the Android log to file to external storage. The code below creates the log file, but no output is sent to the file, so something is obviously wrong with how the handler is configured. Or, perhaps this arrangement cannot be expected to work at all?
The function is called in onCreate() from the main activity.
private void logToFile(String path) {
try {
// Get package name
String packageName = MainActivity.class.getPackage().getName();
String logfileName = path + "/" + packageName + ".log";
Logger logger = Logger.getLogger(packageName);
logger.setLevel(Level.FINE);
FileHandler fileTxt = new FileHandler(logfileName);
SimpleFormatter formatterTxt = new SimpleFormatter();
fileTxt.setFormatter(formatterTxt);
logger.addHandler(fileTxt);
Toast.makeText(this, "Logging to " + logfileName, Toast.LENGTH_LONG).show();
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
Log.i(TAG, "logging to filesystem enabled");
}
To write to the logger declared above (and, thus, the attached handler which writes to a file), the following should be used instead of Log.i(TAG, "message")
private static final Logger logger = Logger.getLogger(TAG);
public void someFunction() {
logger.info("message")
}
These log messages will also appear in logCat/debugger, with the supplied TAG.
P.S. Java logging makes my head hurt...
I was frustrated at having to use Logger instead of standard Logcat Log.d(), Log.e(), etc. so I started using this Frankenstein's monster solution of reading from Logcat into a LogRecord and saving that using FileHandler.
This means you can limit the log file size easily, and retain your detailed Android logs.
But this isn't going to give you continuous output to file. If you don't mind pressing a button or calling it once a session though, then it shouldn't really matter since Logcat is constantly updated anyway.
(I strongly recommend calling from a non-UI thread.)
FileHandler fh=null;
String name;
if ( 0 == Environment.getExternalStorageState().compareTo(Environment.MEDIA_MOUNTED))
name = Environment.getExternalStorageDirectory().getAbsolutePath();
else
name = Environment.getDataDirectory().getAbsolutePath();
name += "/yourapp/yourapp";
try {
fh = new FileHandler(name, 1024*1024, 7, true); //Limit to 7 x 1MB files.
fh.setFormatter(new SimpleFormatter());
//Try to read Logcat.
try {
//Dumps the entire logcat to std output.
Process processD = Runtime.getRuntime().exec("logcat -v long -d");
BufferedReader bufferedReaderD = new BufferedReader(new InputStreamReader(processD.getInputStream()));
String lineD;
while ((lineD = bufferedReaderD.readLine()) != null){
//Send to the file handler.
fh.publish(new LogRecord(Level.ALL, lineD));
}
//Clear the logcat storage. Don't feel like rewriting old records.
Process processC = Runtime.getRuntime().exec("logcat -c");
} catch (IOException e) {
Log.e(TAG, "Could not get Logcat logs.");
e.printStackTrace();
}
} catch (Exception e) {
Log.e("MyLog", "FileHandler exception", e);
} finally {
if (fh != null)
fh.close();
}
May I ask you to guide me how I can accomplish this problem?
I need to compare an inputWord to a string inside a .txt file and if found, return the whole line but if not, show "word not found".
Example:
inputWord: abacus
Text file content:
abaca - n. large herbaceous Asian plant of the banana family.
aback - adv. archaic towards or situated to the rear.
abacus - n. a frame with rows of wires or grooves along which beads are slid, used for calculating.
...
so on
Returns: abacus with its definition
What i am trying to do is compare my inputWord to the words before the " - " (hyphen as delimiter), if they dont match, move to the next line. If they match, copy the whole line.
I hope it doesnt seem like im asking you to "do my homework" but I tried tutorials around different forums and sites. I also read java docs but i really cannot put them together to accomplish this.
Thank you in advance!
UPDATE:
Here's my current code:
if(enhancedStem.startsWith("a"))
{
InputStream inputStream = getResources().openRawResource(R.raw.definitiona);
try {
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
String s = in.readLine();
String delimiter = " - ";
String del[];
while(s != null)
{
s = in.readLine();
del = s.split(delimiter);
if (enhancedStem.equals(del[0]))
{
in.close();
databaseOutput.setText(s);
break;
}
}
in.close();
}
catch (FileNotFoundException e) {
databaseOutput.setText("" + e);
}
catch (IOException e1) {
databaseOutput.setText("" + e1);
}
}
Thanks a lot! Here's what I came up, and it returns the definition of inputs properly but the problem is, when i enter a word not found in the textfile, the app crashes. The catch phrase doesn't seem to work. Have any idea how I can trap it? Logcat says NullPointerExcepetion at line 4342 which is
s = in.readLine();
Assuming that the format of each line in the text file is uniform. This could be done in the following manner :
1) Read the file line by line.
2) Split each line based on the delimiter and collect the split String tokens in a temp String array.
3) The first entry in the temp token array will be the word before the "-" sign.
4) Compare the first entry in the temp array with the search string and return the entire line if there is a match.
Following code could be put up in a function to accomplish this :
String delimiter = "-";
String[] temp;
String searchString = "abacus";
BufferedReader in = new BufferedReader(new FileReader(file));
while (in.readLine() != null) {
String s = in.readLine();
temp = s.split(delimiter);
if(searchString.equals(temp[0])) {
in.close();
return s;
}
}
in.close();
return ("Word not found");
Hope this helps.
you may try like:
myreader = new BufferedReader(new FileReader(file));
String text = "MyInput Word";
while(!((text.equals(reader.readLine())).equals("0")));