For loop causing android app to crash - android

i'm having trouble figuring out why my app is crashing every time i open it. It's only when I uncomment the for loop.
I'm using this idea here to copy files from one directory to another
How to programmatically move, copy and delete files and directories on SD?
however this part (i tried both this way and the same way as in the link above, using children string, etc)
for (File file : files)
{
CopyFile(file, target);
}
keeps causing my application to crash. I tried commenting out just this part and the app runs fine (it doesnt copy anything however as its not accessing a file)
Any ideas?
private void CopyFile(File source, File target) throws IOException {
if (source.isDirectory()){
File[] files = source.listFiles();
for (File file : files)
{
CopyFile(file, target);
}
} else {
InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory());
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
out.write(buf, 0, len);
}
in.close();
out.close();
}

You can't read anything in /data/data except from subdirectories controlled by your app.
/data/data/*packagename*/files
is the path returned by Context.getFilesDir()
/data
is the path returned by Environment.getDataDirectory().
Where exactly do you expect the files to be, and how did they get there originally?

Related

Copying file from raw to external storage

Trying to copy a PDF file (template) to a custom directory in the external storage (non-sd card).
public void copyPDFToExternal(String newFileName) throws IOException {
// Create directory folder if it doesnt exist.
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "pdfFolder");
if (!folder.exists()){
folder.mkdir();
}
// Copy template
InputStream in = getResources().openRawResource(R.raw.pdf_template);
FileOutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory() +
File.separator + "pdfFolder/"+newFileName+".pdf");
byte[] buff = new byte[1024];
int read = 0;
try {
while ((read = in.read(buff)) > 0 ) {
out.write(buff, 0, read);
}
} finally {
in.close();
out.close();
}
}
I have added the following to AndroidManifest.xml, not in the application tag.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Full error: http://pastebin.com/TBtbekiB
If you need me to post anything else let me know.
Where have I gone wrong?
Update: No longer crashes but now doesn't seem to do anything... the mkdirs returns true.
public void copyPDFToExternal(String newFileName) throws IOException {
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/test/");
if (!folder.exists()){
if (!folder.mkdirs()){
eme.setText("Failed");
return;
};
}
InputStream in = getResources().openRawResource(R.raw.ohat);
FileOutputStream out = new FileOutputStream(folder.getAbsolutePath() +"/"+newFileName+".pdf");
byte[] buff = new byte[1024];
int read = 0;
try {
while ((read = in.read(buff)) > 0 ) {
out.write(buff, 0, read);
}
} finally {
in.close();
out.close();
}
}
I've also added a permission request, this is a little long so using pastebin.
http://pastebin.com/KgivWNuc
Edit 2:
So it seems it does work, just the directory cannot be see when the device is connected to a computer (in MTP mode). But I guess that's another issue.
if you are installing in device os version android M and more you need to take permission at runtime. Adding in manifest alone is not sufficient. Refer this for more details.
Can you specify which external storage you are using as you have said it is (non SD Card) because if you are using Environment.getExternalStorageDirectory() then it will give you the path of SD Card Storage, something like this /storage/emulated/0/ where 0 represents primary storage device.

Reading files from a ZIP file in your Android assets folder

I'm reading files from a ZIP file that's located in my Android assets folder using ZipInputStream: it works, but it's really slow, as it has to read it sequentially using getNextEntry(), and there are quite a lot of files.
If I copy the ZIP file onto the SD card, reading is really fast when using ZipFile.getEntry, but I didn't find a way to use ZipFile with the asset file!
Is there any way to access the ZIP in the asset folder in a speedy way? Or do I really have to copy the ZIP to the SD card?
(BTW, in case anybody wonders why I'm doing this: the app is larger than 50 MB, so in order to get it in the Play Store I have to use Expansion APKs; however, as this app should also be put into the Amazon App Store, I have to use another version for this, as Amazon doesn't support Expansion APKs, naturally... I thought that accessing a ZIP file at two different locations would be an easy way to handle this, but alas...)
This works for me:
private void loadzip(String folder, InputStream inputStream) throws IOException
{
ZipInputStream zipIs = new ZipInputStream(inputStream);
ZipEntry ze = null;
while ((ze = zipIs.getNextEntry()) != null) {
FileOutputStream fout = new FileOutputStream(folder +"/"+ ze.getName());
byte[] buffer = new byte[1024];
int length = 0;
while ((length = zipIs.read(buffer))>0) {
fout.write(buffer, 0, length);
}
zipIs.closeEntry();
fout.close();
}
zipIs.close();
}
You can store the uncompressed files directly in assets (i.e. unpack the zip into assets/ folder). This way, you can access the files directly and they will be compressed anyway when you build the APK.
You can create a ZipInputStream in the following way :
ZipInputStream zipIs = new ZipInputStream(context.getResources().openRawResource(your.package.com.R.raw.filename));
ZipEntry ze = null;
while ((ze = zipIs.getNextEntry()) != null) {
FileOutputStream fout = new FileOutputStream(FOLDER_NAME +"/"+ ze.getName());
byte[] buffer = new byte[1024];
int length = 0;
while ((length = zipIs.read(buffer))>0) {
fout.write(buffer, 0, length);
}
zipIs .closeEntry();
fout.close();
}
zipIs .close();

SQLite Database not showing up in File Explorer

I have an SQLite database in my application. When I go to check if the database is created or not in File Explorer, there is no any database file within the data folder. It didn't even show up using the adb shell command. Does this mean that the database hasn't been created yet? Any suggestions on how to solve this?
If you are using an actual device, you will not be able to see or access it from outside unless you root your phone.
If you are using the emulator, the DDMS view will let you navigate to it and pull it from there.
Or, you could have an issue with creating your DB. Without seeing your code we cannot tell.
EDIT
If you want to get the file off of a real device, you'll need to implement a method to copy it from your data directory to someplace where you do have access (such as your SD card). This would do the trick:
public void backup() {
try {
File sdcard = Environment.getExternalStorageDirectory();
File outputFile = new File(sdcard,
"YourDB.bak");
if (!outputFile.exists())
outputFile.createNewFile();
File data = Environment.getDataDirectory();
File inputFile = new File(data, "data/your.package.name/databases/yourDB");
InputStream input = new FileInputStream(inputFile);
OutputStream output = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
output.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
throw new Error("Copying Failed");
}
}

Writing Resources from filesystem in Android

as I need to get a specific Frame from a Website I want to display in an WebView, I decided to grab the .html from the net and save it under file:///data/data//files/file.html. Stroed there I can edit it using regex or String methods.
Now two questions:
Is there a way to bind this file to an resource. e.g. to /res/raw/file.html and get it updated dynamically as i edit it? Or can i write the File directly to the resources?
Is this whole stuff I do there any good or performant at all? I mean maybe there is a better way to get the .html code between two tags from a Webpage and display it via WebView.
Kind regards
Markus
I believe that application assets are readonly. So you cannot write anything to it.
You can though, get access to the internal (device memory) files directory and write your data there. As for automatically updating the file, you'll have to take care of that in your code.
Here is an example of how you would go about writing a file (in my case a stream) to the files directory for your application
// ... code ...
// assumed variables:
// InputStream data, String directory, String filename
File storageLocation = new File(directory, filename)
try {
FileOutputStream outputStream = new FileOutputStream(storageLocation);
byte[] buff = new byte[0x2000];
int bytesRead = 0;
DataOutputStream dos = new DataOutputStream(outputStream);
while( (bytesRead = data.read(buffer)) > 0) { dos.write(buffer, 0, bytesRead); }
dos.flush();
dos.close();
outputStream.close();
} catch (Exception e) {
// TODO: Actually handle the exception
e.printStackTrace();
}
// ... more code ...

Android: read a GZIP file in the ASSETS folder

How can you read GZIP file in Android located in the "ASSETS" (or resources/raw) folder?
I have tried the following code, but my stream size is always 1.
GZIPInputStream fIn = new GZIPInputStream(mContext.getResources().openRawResource(R.raw.myfilegz));
int size = fIn.available();
for some reason the size is always 1. But if Idon't GZIP the file, it works fine.
NOTE:
Using Android 1.5
I met the same problem when reading a gz file from assets folder.
It's caused by the file name of the gz file. Just renaming yourfile.gz to other name like yourfile.bin. It seems Android build system would decompress a file automatically if it thought it's a gz.
public class ResLoader {
/**
* #param res
* #throws IOException
* #throws FileNotFoundException
* #throws IOException
*/
static void unpackResources() throws FileNotFoundException, IOException {
final int BUFFER = 8192;
android.content.res.Resources t = TestingE3d.mContext.getResources();
InputStream fis = t.openRawResource(R.raw.resources);
if (fis == null)
return;
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis,
BUFFER));
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
int count;
FileOutputStream fos = TestingE3d.mContext.openFileOutput(entry
.getName(), 0);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
byte data[] = new byte[BUFFER];
while ((count = zin.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
// Log.v("NOTAG", "writing "+count + " to "+entry.getName());
}
dest.flush();
dest.close();
}
zin.close();
}
}
R.raw.resources is a zip file - this class will decompress all files in that zip to your local folder.
I use this for NDK.
you can access your fils from ndk through:
/data/data//files/
package = package where ResLoader resides
filename = one of files that is in raw/resources.zip
this is the documented behavior of InflaterInputStream.available:
http://java.sun.com/javase/6/docs/api/java/util/zip/InflaterInputStream.html#available()
Returns 0 after EOF has been reached, otherwise always return 1.
abusing available is a common mistake --- in no case can you assume that it tells you the length of a file (though it sometimes happens to do so, as you've noticed). you want to keep calling read(byte[], int, int) until it returns 0. if you want the length to allocate a byte[] up front, you probably want to create a ByteArrayOutputStream and write to that each time you read, and then get a byte[] from that when you exit the loop. this works for all InputStreams in all cases.
It seems that the build system treats .gz files as a special case, even when it's included as a raw resource. Rename the .gz file to have a different extension, say .raw or .bin .
Valid at least for Android Studio 2.2 . I can't find any docs to confirm this is expected behaviour or, better, how to prevent it, but changing the extension at least works around the problem.
What happens if you use AssetManager instead of Resources? Example:
InputStream is = mContext.getAssets().open("myfilegz");
GZIPInputStream fIn = new GZIPINputStream(is);
Internally, Resources is just calling AssetManager; I wonder if somewhere along the way it musses things up.
Try looking at the source for Translate from apps-for-android open source project and see if that helps at all.
They use GZIPInputStream on a raw file in their selectRandomWord() function [line 326] (source pasted below)
public void selectRandomWord() {
BufferedReader fr = null;
try {
GZIPInputStream is =
new GZIPInputStream(getResources().openRawResource(R.raw.dictionary));

Categories

Resources