I wrote this code to save the values of / load values to int arrayScore[10][1000] on/from a text file (ScoreFile.txt), for when the app is closed/opened.
saveData is contained in the onStop() method and loadData is contained in the onCreate() method. When I open/run/close the app, no exception is thrown. The toast says indeed "Data loaded" and "Data saved".
The values of arrayScore[][] do change during the runtime of the app, which is confirmed by these new values appearing on-screen. So during runtime everything works fine.
However, the values of the last session are not loaded when a new session is started, and after that last session ScoreFile.txt is nowhere to be found on my phone.
File scoreFile = new File("ScoreFile.txt");
public void saveData() {
try {
PrintWriter output = new PrintWriter(scoreFile);
int p, q;
for (p = 0; p <= 9; p++) {
for (q = 0; q <= 999; q++) {
output.println(arrayScore[p][q]);
}
}
} catch (Exception e){
Toast.makeText(this, "Exception savedData", Toast.LENGTH_LONG).show();
} finally {
}
Toast.makeText(this, "Data saved", Toast.LENGTH_LONG).show();
}
public void loadData() {
try {
Scanner input = new Scanner(scoreFile);
int p, q;
for (p = 0; p <= 9; p++) {
for (q = 0; q <= 999; q++) {
arrayScore[p][q] = input.nextInt();
}
}
} catch (Exception e) {
Toast.makeText(this, "Exception loadData", Toast.LENGTH_LONG).show();
} finally {
}
Toast.makeText(this, "Data loaded", Toast.LENGTH_LONG).show();
}
A few of points. First, do you have permission to write create a file at that location? Ordinarily, you'd preface the name of your file with the path to internal/external storage for your app, and check that it exists before you do anything. For example (there are many ways to write a file):
File file = new File(context.getFilesDir(), "ScoreFile.txt");
try (final FileOutputStream fos = context.openFileOutput(file, Context.MODE_PRIVATE)){
fos = openFileOutput(filename, Context.MODE_PRIVATE);
//for...
fos.write(/*...*/);
} catch (Exception e) {
e.printStackTrace();
}
Second, have you declared permission for reading and writing to the filesystem in your manifest? You may need runtime permissions for this as well on Oreo+.
Third,of course you see the "Data Saved" toast, because it runs no matter what. Replace it with throws new RuntimeException(e); in your catch and see whether your app crashes. If it does, check LogCat and add the exception to your question.
Fourth, you may need to call flush() on your PrintWriter
Related
So I have a piece of code which works correctly on all devices and emulators I have access to, except one. It's a cheap old Android device, Huawei Y330-U01, running 4.2.2. I'm compiling with com.google.android.gms:play-services-drive:9.8.0. It's absolutely standard, as far as I can tell.
I get the file, which is over a megabyte of plain text, and I can read it character by character, for a few thousand characters (the amount varies, and not between numbers which are powers of two or anything), before getting the error
IOException while testing the stream's first character
java.io.IOException: read failed: EBADF (Bad file number)
at libcore.io.IoBridge.read(IoBridge.java:486)
at java.io.FileInputStream.read(FileInputStream.java:179)
at libcore.io.Streams.readSingleByte(Streams.java:41)
at java.io.FileInputStream.read(FileInputStream.java:175)
at com.suchideas.android.alamode.sync.SyncActivity$b.run(Unknown Source)
Caused by: libcore.io.ErrnoException: read failed: EBADF (Bad file number)
at libcore.io.Posix.readBytes(Native Method)
at libcore.io.Posix.read(Posix.java:123)
at libcore.io.BlockGuardOs.read(BlockGuardOs.java:149)
at libcore.io.IoBridge.read(IoBridge.java:476)
at java.io.FileInputStream.read(FileInputStream.java:179)
at libcore.io.Streams.readSingleByte(Streams.java:41)
at java.io.FileInputStream.read(FileInputStream.java:175)
at com.suchideas.android.alamode.sync.SyncActivity$b.run(Unknown Source)
I'm pretty confident this is something like running out of RAM or disk space (there's certainly more than enough enough space for this file, by hundreds of megabytes, but the device does like to complain about storage) and clearing away something which was actually in use. Again, to reiterate, this code works perfectly on emulators of the same Android version, and all other devices tested.
So. Is there a fix, do you think?
Here's the code, you should be able to fill in the gaps...
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
while (mGoogleApiClient.isConnecting()) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!mGoogleApiClient.isConnected())
return;
}
appFolder = Drive.DriveApi.getAppFolder(mGoogleApiClient);
Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, UPLOADED_DATABASE_NAME))
.build();
DriveApi.MetadataBufferResult metadataBufferResult = appFolder.queryChildren(mGoogleApiClient, query).await();
if (!metadataBufferResult.getStatus().isSuccess()) {
metadataBufferResult.release();
return;
}
MetadataBuffer databaseFileResults = metadataBufferResult.getMetadataBuffer();
if (databaseFileResults.getCount() == 0) {
return;
}
Metadata md = databaseFileResults.get(0);
Log.d(TAG, "Database file retrieved [" + md.getFileSize() + "B]. Created " + md.getCreatedDate() + ", modified " + md.getModifiedDate() + ".");
DriveId databaseFileID = md.getDriveId();
databaseFileResults.release();
metadataBufferResult.release();
DriveFile databaseFile = databaseFileID.asDriveFile();
DriveApi.DriveContentsResult driveContentsResult = databaseFile.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, new DriveFile.DownloadProgressListener() {
#Override
public void onProgress(long downloaded, long expected) {
}
}).await();
if (!driveContentsResult.getStatus().isSuccess()) {
return;
}
DriveContents driveContents = driveContentsResult.getDriveContents();
InputStream in = driveContents.getInputStream();
try {
int c = 0;
for(int i = 0; true; i++) {
c = in.read();
if(c == -1) break;
Log.d(TAG, "Character "+i+": "+(char)c);
}
} catch (IOException e) {
Log.e(TAG, "IOException while testing the stream character", e);
return;
}
Okay, so one can almost certainly do better than this (I don't think you need to read character by character, some buffering is probably okay), but after a few hours of battling, I found a way to avoid triggering the issue on this device.
In practice, I would recommend trying a normal driveContents.getInputStream() first. Then one can catch the sort of errors discussed above, and only turn to this approach if it becomes necessary.
But it works.
The approach: open the DriveContents directly from its FileDescriptor rather than through an InputStream. Gradually build this up in a buffer (I'm just using a StringBuilder here, since this was proof-of-concept). Catch IOExceptions, and if you've successfully read at least some data, start all over again, and keep going, until you reach the end of the string.
private static String safeDriveFileToString(DriveContents driveContents) throws IOException {
StringBuilder sb = new StringBuilder();
InputStream in;
int n = 0, nPrevious = 0;
while(true) {
in = new FileInputStream(driveContents.getParcelFileDescriptor().getFileDescriptor());
try {
int toSkip = n;
while(toSkip > 0) {
toSkip -= in.skip(toSkip);
}
int c;
while ((c = in.read()) != -1) {
sb.append((char) c);
n++;
}
if(c == -1) break;
} catch (IOException e) {
if(nPrevious == n) {
throw e;
} else {
Log.e(TAG, "Ignoring error part-way through a file:", e);
}
nPrevious = n;
}
}
return sb.toString();
}
Wanna know the weirdest thing? After reading this file once with such an approach, it now always works without needing to recourse to this. Absolutely bizarre.
I'm working on an app which stores small amounts of data in /data/data/my_app/files using this code:
private void buildFileFromPreset(String fileName) {
fileName = fileName.toLowerCase();
StandardData data = StandardData.getInstance();
String[] list = data.getDataByName(fileName);
FileOutputStream fos = null;
try {
fos = openFileOutput(fileName, Context.MODE_PRIVATE);
PrintWriter writer = new PrintWriter(fos);
for (int i = 0; i < list.length; i++) {
writer.println(list[i]);
}
writer.close();
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
All works fine when the app gets started, in the onCreate() function of the main activity, I want to check if the files that were created last time are still present:
private String getAppFilesDir() {
ContextWrapper c = new ContextWrapper(this);
return c.getFilesDir().toString();
}
which returns something like:
/data/user/0/my_app/files
I've read some older posts (2012) suggesting this method must work but it doesn't, probably since jellybean.
So my question:
How can I check if the files I created using FileOutputStream and PrintWriter in a previous session still exist?
I hope I provided enough info for you guys to answer (:
I still have not found a solution for this specific problem.
Instead I am now using SQLite so I don't have to worry about these kinds of things.
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();
}
Hello,
I am trying to read a file with a Scanner so I can use the input of the strings to construct other objects. However my scanner is always throwing a NullPointerException when trying to create it. I have a pig.txt text file in the res/raw folder but my scanner can not seem to access it. I do not know what I am doing wrong. I have comment out other code of the method but still get an exception.
public void loadAchievements() {
try {
Scanner s = new Scanner(getResources().openRawResource(R.raw.pig));
/**
* s = s.useDelimiter("."); Scanner StringScanner; StringScanner =
* new Scanner(s.next()); StringScanner =
* StringScanner.useDelimiter(":"); String keep =
* StringScanner.next(); String StringKeeper = StringScanner.next();
* this.achievementBoard.add(new Achievement_Item(keep,
* StringKeeper)); StringScanner.close(); s.close();
**/
} catch (NullPointerException e) {
e.printStackTrace();
System.out.println("NULLPOINTER");
}
}
I had this problem today, and I resolved somehow.
I know that old question, but I would share it if others have stuck.
public class Question {
private int numberOfQuestion;
private String[] myquestion;
public Question(InputStream file_name) {
Scanner scanner = null;
try {
scanner = new Scanner(file_name);
} catch (Exception e) {
Log.d("Question", "Scanner :" + e);
System.exit(1);
}
this.numberOfQuestion = scanner.nextInt();
scanner.nextLine();
myquestion = new String[numberOfQuestion];
for (int i = 0; i < numberOfQuestion; ++i) {
myquestion[i] = scanner.nextLine();
}
scanner.close();
}
---------------------------------------------------------
call:
try {
MyScanner myScanner = new MyScanner(getResources().openRawResource( R.raw.input_question));
} catch (Exception e) {
Log.d("Error", "input_question.txt");
}
openRawResource() method can only be used to open drawable, sound, and raw resources; it will fail on string and color resources. Since your pig.txt is a text file that contains a String, openRawResource() won't be able to open a new stream therefore your stream is null.
I need some input about my code.
Basically, I have a method to load music from Class A
public void onListItemClick(ListView parent, View v, int position, long id){
musicIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToPosition(position);
filePath = cursor.getString(musicIndex);
fileName = new File(filePath).getName();
playMusic();//Play the selected music
}
public void playMusic(){
if(mPlayer.isPlaying()){
mPlayer.reset();
}
try{
mPlayer.setDataSource(filePath);
mPlayer.prepare();
mPlayer.start();
BeatDetection beatDetect = new BeatDetection();
beatDetect.init();
}catch (Exception e){
}
}
That method will call the init() method in Class B
public void init() throws Exception{
energy = 0;
variance = 0;
constant = 0;
isBeat = false;
sensitivity = 0;
dBuffer = new float[sampleRate / bufferSize];
eBuffer = new float[sampleRate / bufferSize];
timer = System.currentTimeMillis();
MusicLoad msc = new MusicLoad();
totalMs = 0;
seeking = true;
//msc.printText();
decode(msc.fileName, 25, 40);
}
In that method, it initializes everything and call the decode() method
public void decode(String path, int startMs, int maxMs)
throws IOException, javazoom.jl.decoder.DecoderException {
debug();
File in = new File(path);
InputStream inStream = new BufferedInputStream(new FileInputStream(in), 8 * 1024);
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
try {
Bitstream bitstream = new Bitstream(inStream);
Decoder decoder = new Decoder();
boolean done = false;
while (! done) {
Header frameHeader = bitstream.readFrame();
if (frameHeader == null) {
done = true;
} else {
totalMs += frameHeader.ms_per_frame();
if (totalMs >= startMs) {
seeking = false;
}
if (! seeking) {
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
if (output.getSampleFrequency() != 44100 || output.getChannelCount() != 2) {
throw new javazoom.jl.decoder.DecoderException("mono or non-44100 MP3 not supported", null);
}
short[] pcm = output.getBuffer();
for (short s : pcm) {
outStream.write(s & 0xff);
outStream.write((s >> 8 ) & 0xff);
}
}
if (totalMs >= (startMs + maxMs)) {
done = true;
}
}
bitstream.closeFrame();
}
byte[] abAudioData = outStream.toByteArray();
calculation(abAudioData);
} catch (BitstreamException e) {
throw new IOException("Bitstream error: " + e);
} catch (DecoderException e) {
Log.w("Decoder error", e);
throw new javazoom.jl.decoder.DecoderException("Error",e);
} finally {
inStream.close();
}
}
Don't mind reading all the code lines. If you guys notice I put debug() in the beginning to see whether the method is called or not. At this point, the debug() is properly called. However, if I put the debug() after the line File in = new File(path);, the debug() will not be called anymore. It seems like the code is stop running at that point.
The ultimate result is, I can load and play the song without any problem. However, the decode() is not called and there is no error whatsoever. I'm stuck at pointing out the problem at this point. So if there's any input please help me.
EDIT: After I tried tracing the "path" variable, it returns NULL so the error is NullPointerException. Seems like the "fileName" variable from Class A is not passed to Class B. Any suggestion?
If you are using Eclipse with ADT then it's very easy to debug your Android apps, just add a breakpoint (probably in the new File(...) line) and see what happens.
My guess here is that File in = new File(path); probably is throwing a IOException in your decode method, that exception is bubbling first to init() and then to playMusic(), where it is caught by try catch block. Your catch is empty so you are not seeing anything. Try debugging as I said or add some logging info in the catch block.
This is just something to look at, but from the doc page
http://developer.android.com/reference/java/io/File.html#File%28java.lang.String%29
"The actual file referenced by a File may or may not exist. It may also, despite the name File, be a directory or other non-regular file."
If you had the path wrong, it may be trying to create the file and you may not have the correct permission to do so. Perhaps: WRITE_EXTERNAL_STORAGE.
I know this post is old, but I just wanted to show how to get the file path to read/write files for others that come across this post as I have:
String filePath = myContext.getFilesDir().getPath().toString() + "/sysout.log";
File file = new File(filePath);
These two lines will create (open if it exists, and overwrite) a file named "sysout.log" in the folder /data/data/com.app.name/files/; myContext is just the current context. Using this technique alleviates problems with defining your own path name. Hope this helps someone.