如果Android开启严格模式情况下会监控APP是否存在未关闭文件流,如果监控到存在未关闭文件流情况会报以下错误:
A resource was acquired at attached stack trace but never released.
See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:180)
at java.io.FileInputStream.<init>(FileInputStream.java:147)
出现这种情况基本是流对象如FileInputStream没有调用close(),或者try{}catch{},没有调用finally()
对于这种问题有三种解决方案:
- Java 7 之后,可以使用try-with-resource方式处理
- Java最基础的手动关闭的形式try-catch-finally
- Kotlin使用
use
函数
使用try-with-resource方式
Java 7 之后,可以使用try-with-resource方式处理,示例代码如下
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
// 自定义类实现AutoCloseable接口
public class MyFileInputStream extends FileInputStream implements AutoCloseable {
public MyFileInputStream(File file) throws IOException {
super(file);
}
@Override
public void close() throws IOException {
// 重写close方法
System.out.println("Closing MyFileInputStream");
super.close();
}
}
public class Test {
public static void main(String[] args) {
// 使用try-with-resources语句自动关闭资源
try (MyFileInputStream fis = new MyFileInputStream(new File("test.txt"))) {
// 在try块中使用资源
int data = fis.read();
while (data != -1) {
System.out.print((char) data);
data = fis.read();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-catch-finally
使用Java最基础的手动关闭的形式try-catch-finally,示例代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public void saveFile(boolean externalStorage) {
String s = "12345";
File file;
FileOutputStream fos = null;
try {
file = externalStorage ? new File(getExternalFilesDir(null), "log") : new File(getFilesDir(), "log");
fos = new FileOutputStream(file);
fos.write(s.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭文件流
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用use函数
use
函数是kotlin标准库中的一个扩展函数,它可以用于自动关闭实现了Closeable
或AutoCloseable
接口的资源。这些接口定义了一个close()
方法,用于释放资源。例如,文件流,网络连接,数据库连接等都是需要关闭的资源。
use
函数的定义如下:
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R
使用 use函数读取文件示例代码:
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
fun copyFile(source: File, target: File) {
// 使用use函数自动关闭输入流和输出流
FileInputStream(source).use { input ->
FileOutputStream(target).use { output ->
// 在use块中使用输入流和输出流
val buffer = ByteArray(1024)
var bytes = input.read(buffer)
while (bytes >= 0) {
output.write(buffer, 0, bytes)
bytes = input.read(buffer)
}
}
}
}