First I will say I've researched various solutions on StackOverflow and elsewhere and none have solved my issue. I'll admit that my knowledge in this area is somewhat lacking, so sorry for being all noobish.
I want to do what I assume to be a simple thing. My app creates a file on start up if it does not exist yet, and populates it with 30 "0.0", each on a different line (This is done successfully).
Then when you beat a level, the intent is to have the file read, the 0.0's and assign each one to an element of an array, assign the time remaining (for example, 2.5) to the appropriate spot ([0] for the first level, [1] for the second level, etc), and write it back to the file to keep track of how much time was remaining when the player beat each level.
The problem becomes, though it does write the score in the appropriate spot back into the file (I'm testing level 1 so in spot [0]), all of the other 0.0's become "null". So I know there is a mistake somewhere that I must not be seeing, and after several hours over several days of trying various solutions, I finally decided to ask for help here. This is the code below:
try {
String[] scoreArray = new String[30];
File sdCard = Environment.getExternalStorageDirectory();
File myFile = new File(sdCard.getAbsolutePath());
// myFile.createNewFile();
File file = new File(myFile, "RLGLscores.txt");
FileOutputStream fOut = new FileOutputStream(file);
String newLine = System.getProperty("line.separator");
OutputStreamWriter myOutWriter =
new OutputStreamWriter(fOut);
FileInputStream fis = new FileInputStream(file);
BufferedReader myReader = new BufferedReader(
new InputStreamReader(fis));
String data = "";
int i = 0;
while ((data = myReader.readLine()) != null) {
scoreArray[i] = data;
i++;
}
myReader.close();
scoreArray[0] = timerStringFormat;
for (int j = 0; j < 30; j++) {
myOutWriter.write(scoreArray[j] + newLine);
}
myOutWriter.close();
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
timerStringFormat is the String that holds the time remaining in the form of a String. Again I'm rather new to this. My game is nearly complete, I'm amazed I got as far as I have. But any help would be greatly appreciated.
Opening the file for writing truncates it to zero length. If you later try to read from it you just see an empty file.
To fix that, first read the contents, close the reader, and then open the output stream and write the modified contents back.
Related
In my application the user can choose a file using the chooser Intent, which will then be "imported" into the application and saved in internal storage for security reasons. This all worked fine and still does on some devices, but for example on the Google Pixel on Android 7.1.1 it only functions normally for the first 4-6 files and afterwards it acts very odd.
The performance was going down drastically so I checked my storage usage and found that it was continuously growing, although the file I was supposed to be saving was less than 1mb large. Importing a file would cause the amount of storage taken by my app to rise past 500mb and upward. I can't seem to find the cause for this.
The method I am using to save the files which is called in an async background task:
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
OutputStream fos = new FileOutputStream(file);
int size = 0;
InputStream fis = getContentResolver().openInputStream(uri);
try{
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] buf = new byte[1024];
int len = 1024;
while((len = bis.read(buf,0,len)) != -1){
bos.write(buf,0,len);
size = size+1024;
Log.v("Bytes written",""+size);
}
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if(bis != null) bis.close();
if(bos != null) bos.close();
if(fis != null) fis.close();
if(fos != null) fos.close();
}catch(IOException e){
e.printStackTrace();
}
}
return Uri.fromFile(file);
The Uri which this function returns is then saved in an SQLite Database to be used later.
I appreciate all kinds of tips as to where this memory usage could be coming from.
Btw, this did not result from an update on the phone nor from any changes in my code, as it was working the last time I tested it and I haven't changed anything since.
I see a couple of things to correct:
1) The signature of the write method doesn't seem correct, if you write from a buffer you should use write(buff, offset, length).
2) You read into the buffer once, so it should be enugh to write out the buffer once too.
3) If you need to read the the buffer more than once, and write out the values more than once, use a while, not a do while. You have no garantee that the read operation was succesfull.
Ref to write method in Android Developer
I had an additional method which would append an index to a file added multiple times eg. "file.pdf", "file1.pdf","file2.pdf". This method wasn't correct, leading to an endless loop of creating a new file and appending an index. I managed to fix the problem by changing this method to avoid looping.
In retrospect I should have included that in my question.
I've got a rather odd problem. I'm writing an Android application using the Xamarin framework, and I also have an iOS version of the same app also written in Xamarin. In the app the user can send photos and videos to their friends, and their friends may be on either iOS or Android. This all works fine, and videos taken on an iPhone can be played on an Android device and vice versa.
The problem I am having is when I try to programmatically save a video to the Android gallery, then that video is not able to be played in the gallery. It does appear that the video data it's self is actually copied, but the video is somehow not playable.
My videos are encoded to the mp4 format using the H.264 codec. I believe this is fully supported in Android, and like I said the videos play just fine when played via a VideoView in the app.
The code I am using to copy the videos to the gallery is below. Does anyone have any idea what I am doing wrong here?
public static void SaveVideoToGallery(Activity activity, String filePath) {
// get filename from path
int idx = filePath.LastIndexOf("/") + 1;
String name = filePath.Substring(idx, filePath.Length - idx);
// set in/out files
File inFile = new File(filePath);
File outDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryMovies);
File outFile = new File(outDir, name);
// Make sure the Pictures directory exists.
outDir.Mkdirs();
// save the file to disc
InputStream iStream = new FileInputStream(inFile);
OutputStream oStream = new FileOutputStream(outFile);
byte[]data = new byte[iStream.Available()];
iStream.Read();
oStream.Write(data);
iStream.Close();
oStream.Close();
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.ScanFile(
activity.ApplicationContext,
new String[] { outFile.ToString() },
null,
null);
}
NOTE: I know this is all in C#, but keep in mind that all the Xamarin framework does is provide an API to the native Android methods. Everything I am using is either Java or Android backed classes/functions.
Thanks!
Your issue is in this code snippet:
byte[]data = new byte[iStream.Available()];
iStream.Read();
oStream.Write(data);
There are a few issues here:
You never read the files contents into the data buffer; iStream.Read() will only read a single byte and return it as an integer.
new byte[iStream.Available()] will only allocate the amount of data bytes that are available to be read without blocking. It isn't the full file. See the docs on the available method.
oStream.Write(data) writes out a garbage block of data as nothing is ever read into it.
The end result is the outputted video file is just a block of empty data hence why the gallery cannot use it.
Fix it reading in the data from the file stream and then writing them into the output file:
int bytes = 0;
byte[] data = new byte[1024];
while ((bytes = iStream.Read(data)) != -1)
{
oStream.Write (data, 0, bytes);
}
Full sample:
public static void SaveVideoToGallery(Activity activity, String filePath) {
// get filename from path
int idx = filePath.LastIndexOf("/") + 1;
String name = filePath.Substring(idx, filePath.Length - idx);
// set in/out files
File inFile = new File(filePath);
File outDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryMovies);
File outFile = new File(outDir, name);
// Make sure the Pictures directory exists.
outDir.Mkdirs();
// save the file to disc
InputStream iStream = new FileInputStream(inFile);
OutputStream oStream = new FileOutputStream(outFile);
int bytes = 0;
byte[] data = new byte[1024];
while ((bytes = iStream.Read(data)) != -1)
{
oStream.Write (data, 0, bytes);
}
iStream.Close();
oStream.Close();
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.ScanFile(
activity.ApplicationContext,
new String[] { outFile.ToString() },
null,
null);
}
I am facing a problem downloading PNG images from my server to my Android app. The problem is specific to PNG images (JPG works fine), and the issue is that the downloaded files are corrupt images. I will explain in more details, below.
Scenario :
I need to download JPG and PNG images from my server, and display them to the user of the Android app.
Issue :
The JPG images get downloaded without an issue. But the downloaded PNG files are corrupt. I have double checked the source of the images at my server, and they are proper. Its only the downloaded PNG files, that are corrupt. So, the problem probably lies in the way I am downloading them in Android.
Code Sample :
URL imageURL;
File imageFile = null;
InputStream is = null;
FileOutputStream fos = null;
byte[] b = new byte[1024];
try {
// get the input stream and pass to file output stream
imageURL = new URL(image.getServerPath());
imageFile = new File(context.getExternalFilesDir(null), image.getLocalPath());
fos = new FileOutputStream(imageFile);
// get the input stream and pass to file output stream
is = imageURL.openConnection().getInputStream();
// also tried but gave same results :
// is = imageURL.openStream();
while(is.read(b) != -1)
fos.write(b);
} catch (FileNotFoundException e) {
} catch (MalformedURLException e) {
} catch (IOException e) {
} finally {
// close the streams
try {
if(fos != null)
fos.close();
if(is != null)
is.close();
} catch(IOException e){
}
}
Any pointers on how I can work on this, will be very appreciated.
Note :
Since this is happening in a service, there are no problems of doing this inside an AsyncTask.
The problem is here
while(is.read(b) != -1)
fos.write(b);
This is wrong, because in each iteration it will write the full buffer (1024 bytes) to the file. But the previous read could have read less bytes than than (almost surely on the last loop, unless the image lenght happens to be exactly a multiple of 1024). You should check how many bytes were read each time, and write that amount of bytes.
int bytesRead;
while( (bytesRead = is.read(b)) != -1)
fos.write(b,0,bytesRead );
Your error makes you write always files with sizes that are multiple of 1024 - which of course is not the case in general. Now, what happens when a image is saved with extra trailing bytes depends on the format and on the image reader. In some cases, it might work. Still, it's wrong.
BTW: never swallow exceptions - even if that's not the problem today, it might be tomorrow and you might spend hours finding the problem.
So in this app I made, The user makes a project and when they save, the number of frames is saved to numberFrames.txt on the SD card. Then I retrieve the file in another class. Only thing is that nFrames = 50 when i show a toast of nFrames to the screen after I run this code. The only initializing of nFrames I do is to zero right above this code, which is located in the onCreate().
File sdcardLocal = Environment.getExternalStorageDirectory();
File dir = new File (sdcardLocal.getAbsolutePath() + "/Flipbook/"+customizeDialog.getTitle()+"/");
dir.mkdirs();
File fileNum = new File(dir, "numberFrames.txt");
FileWriter myFileWriter = null;
try {
myFileWriter = new FileWriter(fileNum);
} catch (IOException e) {
e.printStackTrace();
}
BufferedWriter out = new BufferedWriter(myFileWriter);
try {
String text = bitmaps.size()+"";
out.write(text);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
I retrieve the file like this. I have no idea where this "50" value for nFrames came from as there are no loops around this and I know for sure that the particular project saved has only 3 frames. Why is this?
FileInputStream is = null;
BufferedInputStream bis = null;
try {
is = new FileInputStream(new File(mFolderDialog.getPath()+"/numberFrames.txt"));
bis = new BufferedInputStream(is);
nFrames = bis.read();
}catch (IOException e) {
e.printStackTrace();
}
You are writing out a string, and then reading the first byte as an integer. 50 is the ascii code for the '2' character.
You can use BufferedReader.readLine to read the entire first line of the file as a String, and then Integer.parseInt to convert that to an integer.
Also, I would take a closer look at your application's workflow. You don't give much information, but saving a file with a single integer value to the sdcard has a certain "smell" to it :). Have you looked at using a database, or maybe store the text file in your application's directory instead?
I'm writing to a file using the code below:
File file = new File(getCacheDir(), "cachefile");
FileOutputStream fos = new FileOutputStream(file);
StringBuilder cachetext = new StringBuilder();
Iterator bri = brands.iterator();
Iterator bli = brand_id.iterator();
while(bli.hasNext()) {
cachetext.append(bli.next() + "|" + bri.next() + System.getProperty("line.separator"));
}
fos.write(cachetext.toString().getBytes());
fos.close();
This works fine - no errors and the file ends up containing what I expect it to contain. When I go to read it via openFileInput(), however, I get an exception telling me that path separators are not allowed
FileInputStream fis = openFileInput(getCacheDir() + "/cachefile");
Fair enough, that contains a slash, but how else can I specify the path of the file I want to open? There must be a way to do this, of course, but I can't find answers via Google ('read', 'cache' and 'file' not being the most niche of terms ...) so I thought I'd try the human touch. Thanks in advance!
you do it pretty much the same way you created the output file:
FileInputStream fis = new FileInputStream(new File(getCacheDir(), "cachefile"));