资源泄漏:流永远不会关闭

时间:2012-10-16 11:02:54

标签: android warnings

在我的真实项目中重现问题的简短方法。环境:Android SDK 1.16,Eclipse 4.2.0,Windows。创建默认的Android应用程序并将以下代码添加到MainActivity.java:

private void Save1(boolean externalStorage)
{
    String s = "12345";
    File file;
    FileOutputStream fos = null;

    if ( externalStorage )
    {
        try
        {
            file = new File(getExternalFilesDir(null), "log");
            fos = new FileOutputStream(file);                  // Resource leak: 'fos' is never closed
        }
        catch(FileNotFoundException e)
        {
            return;
        }
    }
    else
    {
        try
        {
            fos = openFileOutput("log", Context.MODE_PRIVATE);
        }
        catch(FileNotFoundException e)
        {
            return;
        }
    }

    try
    {
        fos.write(s.getBytes());
        fos.close();
    }
    catch(IOException e)
    {
        return;
    }
}

private void Save2(boolean externalStorage)
{
    String s = "12345";
    File file;
    FileOutputStream fos = null;

    try
    {
        file = new File(getExternalFilesDir(null), "log");
        fos = new FileOutputStream(file);                  // OK
    }
    catch(FileNotFoundException e)
    {
        return;
    }

    try
    {
        fos.write(s.getBytes());
        fos.close();
    }
    catch(IOException e)
    {
        return;
    }
}
fos = new FileOutputStream(file)函数中

Save1,警告:Resource leak: 'fos' is never closed

Save2函数中的同一行:没有警告。

请不要发送未经测试的答案,问题并不像看起来那么简单。将fos.close()添加到函数的不同部分并不会有帮助。

3 个答案:

答案 0 :(得分:2)

如果我在if块中添加了一个finally块,就像这样:

if (externalStorage) {
            try {
                fos = new FileOutputStream(new File(getExternalFilesDir(null),
                        "log"));
            } catch (FileNotFoundException e) {
                return;
            } finally {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            try {
                fos = openFileOutput("log", Context.MODE_PRIVATE);
            } catch (FileNotFoundException e) {
                return;
            }
        }

这很有趣......

所以我的猜测是,所以如果你在try块中打开一个Stream并且catch块有一个return语句,那么应该有一个关闭流的finally块。

像这样......

在eclipse中的一个简单的java项目中尝试了相同的代码并且仍然收到了警告。所以它看起来与lint或android无关。它看起来像是eclipse编译器问题。以下是代码,我不得不创建一个虚拟的openFileOutput()方法,因为它不可用于java:

private void Save1(boolean externalStorage) {
    String s = "12345";
    FileOutputStream fos = null;

    if (externalStorage) {
        try {
            fos = new FileOutputStream(new File("c://", "log"));
        } catch (FileNotFoundException e) {
            return;
        }
    } else {
        try {
            fos = openFileOutput("log", -1);
        } catch (FileNotFoundException e) {
            return;
        }
    }

    try {
        fos.write(s.getBytes());
        fos.close();
    } catch (IOException e) {
        return;
    }
}

/**
 * @param string
 * @param i
 * @return
 */
private FileOutputStream openFileOutput(String string, int i)
        throws FileNotFoundException {
        return null;
}

答案 1 :(得分:1)

这不是一个答案,但为了清楚OP和其他读者而不是评论,这里添加了。

我使用当前版本的平台工具链(2012年10月14日修订版)在IDEA 11.2 API 15中对此进行了测试,并且没有lint警告,编译错误或运行时错误。我通过创建异常并将useExternalStorage设置为true和false来强制该方法遍历每个路径。

我猜这是你的工具链中的lint / compile错误,或者可能是Eclipse(尽管不太可能,Eclipse本身是否会像这样进行任何检查?)。

[编辑]

只是一个想法,(我会测试但我忘记了如何使用Eclipse)但是FileInputStream(文件)可能会抛出一个SecurityException,它将被抛出到你的调用堆栈中的某个地方。如果你抓住它会发生什么?

[编辑]

这是我得到的最接近的警告,并没有任何相关性。我确信警告不是由你决定的。

Screen shot for IDEA 11.2, API 15, SDK tools rev 14

答案 2 :(得分:0)

如果Exceptionfos将无法关闭。将finally添加到try-catch可以解决此问题。

    try
    {
        fos = openFileOutput("log", Context.MODE_PRIVATE);
    }
    catch(FileNotFoundException e)
    {
        return;
    }
    //add this:
    finally {
        if (fos != null) {
            fos.close();
        }
    }
相关问题