FileOutputStream 因 FileNotFoundException 失败,即使文件明显存在、可写且具有权限

发布于 2024-12-13 07:57:02 字数 5719 浏览 1 评论 0原文

虽然我对 Android 比较陌生,但我有基于 Java 和 C 的编程经验,并且我目前正在使用 Eclipse 以及常用的工具集进行开发。我已经阅读了有关该主题的大部分帖子,并且我相信我已经包含/应用了所有建议和测试。我之前曾使用 FileOutputStream 写入内部、特定于应用程序的文件,为 L8 构建,没有任何问题。我现在尝试使用 Build L7 for Android 2.1 写入 SD 卡上的文件。以下代码来自具有 3 个按钮(写入、读取和发送)的单个活动,我用它来测试基本代码。尽管导致 FileOutputStream (FOS) 构造函数的所有包含的测试(存在、可写以及 createNewFile 或 mkdirs 上的 IOException)都通过了 AOK,但 FOS 构造失败,抛出 FileNotFoundException,请参见下文。我已逐步完成调试并确认问题,请参阅底部的 LogCat。它通过 ADB 在 Eclipse 标准模拟器上运行,构建中包含一个 256kB 的 SD 卡。

<块引用>

来自我的 onw createExternalStorageFile() 方法。

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;

>

我的清单文件包含使用权限声明,如下所示:

>

<?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>

>

那么这超出了声明范围,应该没问题吧?

任何人都可以帮助解决为什么 FileOutputStream 失败的这个谜题,即使我所有的测试似乎都确认它应该工作?

> 日志猫: 11-02 15:40:54.754:DEBUG/MediaScannerService(154):开始扫描外部卷 11-02 15:40:54.764: 详细/MediaProvider(154): /sdcard 卷 ID: 300427547 11-02 15:40:54.894:INFO/System.out(202):调试器已解决(1479) 11-02 15:40:55.024:详细/MediaProvider(154):附加卷:外部 11-02 15:40:55.904: VERBOSE/MediaScanner(154): pruneDeadThumbnailFiles... android.database.sqlite.SQLiteCursor@44c434f0 11-02 15:40:55.915:详细/ MediaScanner(154):/pruneDeadThumbnailFiles ... android.database.sqlite.SQLiteCursor@44c434f0 11-02 15:40:55.925:调试/MediaScanner(154):预扫描时间:715ms 11-02 15:40:55.955:调试/MediaScanner(154):扫描时间:4ms 11-02 15:40:55.955:调试/MediaScanner(154):后扫描时间:55ms 11-02 15:40:55.955:调试/MediaScanner(154):总时间:774ms 11-02 15:40:55.964:DEBUG/MediaScannerService(154):完成扫描外部卷 11-02 15:44:50.934:调试/KeyguardViewMediator(52):pokeWakelock(5000) 11-02 15:44:51.334:调试/KeyguardViewMediator(52):pokeWakelock(5000) 11-02 15:44:51.384:INFO/ActivityManager(52):显示的活动 org.eddiem.adeveloper.filesendl7/.FileSendL7Activity:239793 毫秒(总计 255760 毫秒) 11-02 15:44:51.394:INFO / ARAssembler(52):在757079 ns内的[0x46ac60:0x46ad2c]处生成扫描线__00000077:03545404_00000A04_00000000 [29 ipp](51 ins) 11-02 15:44:51.414:信息/ARMAssembler(52):在657626 ns内的[0x46ad30:0x46aeb8]处生成扫描线__00000177:03515104_00001A01_00000000 [73 ipp](98英寸) 11-02 15:45:05.884:DEBUG/FileSendL7Activity(202):完整文件路径为:/sdcard/testFile.txt 11-02 15:45:22.484:错误/FileSendL7Activity(202):fOS-FileNotFoundException 11-02 15:45:22.484:错误/FileSendL7Activity(202):java.io.FileNotFoundException:/sdcard/testFile.txt 11-02 15:45:22.484:错误/FileSendL7Activity(202):在org.apache.harmony.luni.platform.OSFileSystem.open(OSFileSystem.java:244) 11-02 15:45:22.484:错误/FileSendL7Activity(202):在java.io.FileOutputStream。(FileOutputStream.java:97) 11-02 15:45:22.484:错误/FileSendL7Activity(202):在java.io.FileOutputStream。(FileOutputStream.java:168) 11-02 15:45:22.484:错误/FileSendL7Activity(202):在java.io.FileOutputStream。(FileOutputStream.java:147) 11-02 15:45:22.484:错误/FileSendL7Activity(202):在org.eddiem.adeveloper.filesendl7.FileSendL7Activity.creatExternalStorageFileOS(FileSendL7Activity.java:149) 11-02 15:45:22.484:错误/FileSendL7Activity(202):在 org.eddiem.adeveloper.filesendl7.FileSendL7Activity.access$0(FileSendL7Activity.java:124) 11-02 15:45:22.484:错误/FileSendL7Activity(202):在 org.eddiem.adeveloper.filesendl7.FileSendL7Activity$1.onClick(FileSendL7Activity.java:176) 11-02 15:45:22.484: 错误/FileSendL7Activity(202): 在 android.view.View.performClick(View.java:2364)

>

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

老街孤人 2024-12-20 07:57:02

阅读本文可以学到很多教训。
首先确保您的 Eclipse 或其他 IDE 已完全更新,并且所有包和工具均已正确加载。下一课是确保您了解所有工具的工作原理!请参阅下文 - DDMS 中的 File_Explorer。
与这些明显的编码问题相关的最大的单一问题是,通过 Eclipse 调试工具提供的编码实验的结果向我展示了与 Android 文档中描述的完全不同的图片。我自己的偏执造成了其余的问题,我只是包含了许多版本的代码片段和太多的测试。

技术问题/答案如下:

  1. Android 2.1(API-L7) 和 2.2(API-L8) 实现不同的 sdcard 文件结构。所以 getExternalStorageDirectory() 返回 /sdcard/
    L7 和 L8 的 /mnt/sdcard/。

  2. 外部存储的 Android 文档,位于 http:// developer.android.com/guide/topics/data/data-storage.html
    正确的;对于 2.1(L7)+ 使用 Environment.getExternalStorageDirectory()
    并且仅对 2.2(L8)+ 使用 Context.getExternalFilesDir(null)

  3. 构造 File 对象不会根据提供的名称创建文件或目录。您必须使用 mkdirs() 和
    createNewFile() 如果你想实际创建一个目录树
    超出根目录和其中的文件。然而,实际的文件是
    当您成功打开 FileOutputStream 时创建,因此有
    通常不需要使用createNewFile()。你必须使用 mkdirs 如果你想要的话
    创建您自己的目录。

  4. 在 Eclipse 中创建并与模拟器一起使用的 Android 虚拟设备实际上会创建目录和文件,您可以看到
    这些在调试期间使用 DDMS 上的File_Explorer 选项卡。笔记:
    这些目录和文件是持久的并且不会自动
    已删除。运行后使用工具自行删除文件
    或调试您的代码。

  5. 最后,使用字节数组的 BufferedOutputStream 是小文件和/或多次写入的首选。文件写入用于
    字符数组,在所有情况下您都必须包含在您的
    Manifest.XML

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

最后对冗长的问答表示歉意,但我希望很多人能够阅读并学习我的痛苦。 :o)

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:

  1. 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.

  2. 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)+

  3. 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.

  4. 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.

  5. 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)

不醒的梦 2024-12-20 07:57:02

试试这个

if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        Log.e("TEST", "this is bad");
}

File file = new File(getExternalFilesDir(null), "test.csv");

try {
    FileOutputStream fos = new FileOutputStream(file);
fos.write(...);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Try this

if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        Log.e("TEST", "this is bad");
}

File file = new File(getExternalFilesDir(null), "test.csv");

try {
    FileOutputStream fos = new FileOutputStream(file);
fos.write(...);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文