Although I am relatively new to Android, I have experience in Java and C based programming and I am currently using Eclipse, with the usual toolset, for development. I have read most of the posts around this subject and I believe that I have included/applied all the recommendations and tests. I have previously used FileOutputStream to write to internal, application specific, files, build for L8, without any problem. I am now tring to write to a file on the SD Card, with Build L7 for Android 2.1. The following code is from the single activity with 3 Buttons (write, read & send) that I am using to test the basic code. Although all the included tests (exists, writeable and an IOException on createNewFile, or mkdirs) leading up to the FileOutputStream (FOS) constructor pass AOK, the FOS construct fails, throwing the FileNotFoundException, see below. I have stepped through on debug and confirmed problem, see the LogCat at the bottom. This is running on the Eclipse standard emulator via the ADB with an SD-Card included in the build for 256kB.
From my onw createExternalStorageFile() method.
File file = null;
file = new File(Environment.getExternalStorageDirectory(), mfileName);
if(file != null) {
//file.mkdirs();
try {
file.createNewFile();
} catch (IOException e1) {
Log.e(TAG, "createNewFile() failed!", e1);
return false;
}
}
if(!file.exists()) {
Log.d(TAG, "file does not exist!");
}
if(!file.canWrite()) {
Log.d(TAG, "cannot write to file!");
}
Log.d(TAG, "full file-path is: " + file.toString());
FileOutputStream fOS = null;
try {
//fOS = new FileOutputStream(file);
fOS = new FileOutputStream(file.toString());
// *** THIS THROW THE FILENOTFOUNDEXCEPTION ***
} catch (FileNotFoundException e1) {
Log.e(TAG, "fOS-FileNotFoundException", e1);
return false;
}
// fOS IS STILL NULL - HOW CAN THIS BE!
if(fOS != null) {
try {
fOS.write(TESTDATA.getBytes());
fOS.close();
} catch (IOException e1) {
Log.e(TAG, "IOException from fOS-write()!", e1);
return false;
}
Log.d(TAG, "fos-fd is: " + fOS.toString());
}
return true;
>
My Manifest file contains the uses-permission declaration as follows:
>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eddiem.adeveloper.externalfilesend"
android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<activity android:name=".ExternalFileSendActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
>
So this is outside the declaration and should be OK?
Can anyone please help solve this riddle of why FileOutputStream is failing even though all my tests appear to confirm it should work?
> LogCat: 11-02 15:40:54.754: DEBUG/MediaScannerService(154): start scanning volume external 11-02 15:40:54.764: VERBOSE/MediaProvider(154): /sdcard volume ID: 300427547 11-02 15:40:54.894: INFO/System.out(202): debugger has settled (1479) 11-02 15:40:55.024: VERBOSE/MediaProvider(154): Attached volume: external 11-02 15:40:55.904: VERBOSE/MediaScanner(154): pruneDeadThumbnailFiles... android.database.sqlite.SQLiteCursor@44c434f0 11-02 15:40:55.915: VERBOSE/MediaScanner(154): /pruneDeadThumbnailFiles... android.database.sqlite.SQLiteCursor@44c434f0 11-02 15:40:55.925: DEBUG/MediaScanner(154): prescan time: 715ms 11-02 15:40:55.955: DEBUG/MediaScanner(154): scan time: 4ms 11-02 15:40:55.955: DEBUG/MediaScanner(154): postscan time: 55ms 11-02 15:40:55.955: DEBUG/MediaScanner(154): total time: 774ms 11-02 15:40:55.964: DEBUG/MediaScannerService(154): done scanning volume external 11-02 15:44:50.934: DEBUG/KeyguardViewMediator(52): pokeWakelock(5000) 11-02 15:44:51.334: DEBUG/KeyguardViewMediator(52): pokeWakelock(5000) 11-02 15:44:51.384: INFO/ActivityManager(52): Displayed activity org.eddiem.adeveloper.filesendl7/.FileSendL7Activity: 239793 ms (total 255760 ms) 11-02 15:44:51.394: INFO/ARMAssembler(52): generated scanline__00000077:03545404_00000A04_00000000 [ 29 ipp] (51 ins) at [0x46ac60:0x46ad2c] in 757079 ns 11-02 15:44:51.414: INFO/ARMAssembler(52): generated scanline__00000177:03515104_00001A01_00000000 [ 73 ipp] (98 ins) at [0x46ad30:0x46aeb8] in 657626 ns 11-02 15:45:05.884: DEBUG/FileSendL7Activity(202): full file-path is: /sdcard/testFile.txt 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): fOS-FileNotFoundException 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): java.io.FileNotFoundException: /sdcard/testFile.txt 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at org.apache.harmony.luni.platform.OSFileSystem.open(OSFileSystem.java:244) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at java.io.FileOutputStream.(FileOutputStream.java:97) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at java.io.FileOutputStream.(FileOutputStream.java:168) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at java.io.FileOutputStream.(FileOutputStream.java:147) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at org.eddiem.adeveloper.filesendl7.FileSendL7Activity.creatExternalStorageFileOS(FileSendL7Activity.java:149) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at org.eddiem.adeveloper.filesendl7.FileSendL7Activity.access$0(FileSendL7Activity.java:124) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at org.eddiem.adeveloper.filesendl7.FileSendL7Activity$1.onClick(FileSendL7Activity.java:176) 11-02 15:45:22.484: ERROR/FileSendL7Activity(202): at android.view.View.performClick(View.java:2364)
>
Thanks
There are a number of lessons to be learned from reading this. Firstly make sure that your Eclipse or other IDE is completely updated and that all the packages and tools are loaded correctly. The next lesson is to make sure that you know how all the tools work! See below - File_Explorer in DDMS. The biggest single issue that was associated with these apparent coding problems was that the results from my coding experiments, as provided through the Eclipse debugging tools, were showing me a completely different picture to that described in the Android documentation. My own paranoia created the rest of the problems and I simply included to many versions of code snippets and too many tests.
The technical issue/answers are a follows:
Android 2.1(API-L7) and 2.2(API-L8) implement a different sdcard file structure. So getExternalStorageDirectory() returns /sdcard/ for the L7 and /mnt/sdcard/ for the L8.
The Android documentation for External Storage on http://developer.android.com/guide/topics/data/data-storage.html is correct; Use Environment.getExternalStorageDirectory() for 2.1(L7)+ and only use Context.getExternalFilesDir(null) for 2.2(L8)+
Contructing a File object does not create the file or the directories for the names provided. You must use the mkdirs() and createNewFile() if you want the actually create a directory tree beyond the root and the file within it. However, an actual file is created when you successfully open a FileOutputStream, so there is often no need to use createNewFile(). You MUST use mkdirs is you want to create your own directories.
The Android Virtual Devices created in Eclipse and used with the Emulator actually do create directories and files and you can see these using the File_Explorer tab on the DDMS during debug. NOTE: These directories and files are persistent and NOT automatically deleted. Use the the tools to delete the files yourself after you run or debug your code.
Finally BufferedOutputStream using byte arrays is the preferred option for small files and/or multiple writes. FileWrite is used for char arrays and in all cases you must include in your Manifest.XML
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
A final apology for the wordy Q&A, but I hope lots of people read and learn for my pain. :o)