我已经开发一个应用程序大约两个月了,但最近我在尝试在我的应用程序特定文件目录上创建、写入和读取文件时遇到了问题。
我正在创建文件并在其上写入内容,就像 this Android 开发人员指南示例中所示,但我的应用程序不断出现以下异常:
java.io.IOException: Permission denied
at java.io.UnixFileSystem.createFileExclusively0(Native Method)
at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
at java.io.File.createNewFile(File.java:1006)
at com.adoc.apktest.Tools.writeFile(Tools.java:36)
at com.adoc.apktest.GeneralFunctions.testCallLog(GeneralFunctions.java:71)
at com.adoc.apktest.Tests.run(Tests.java:98)
在我之前提到的文章中说:
您的应用不需要任何系统权限即可读取和写入这些目录中的文件。
所以我无法弄清楚为什么每次尝试创建并写入文件时都会抛出此异常。
以下是与此问题相关的代码:
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
String testID = getIntent().getStringExtra("testID");
Tools tools = new Tools(this);
Tests tests = new Tests(testID, this, tools);
tests.start();
测试.java
public Tests(String testID, Context context, Tools tools) {
this.testID = testID;
this.context = context;
this.tools = tools;
}
@Override
public void run() {
super.run();
try {
switch (testID) {
...
case "generalFunctions": {
GeneralFunctions.testCallLog(context, tools, "016");
...
通用函数.java
public static void testCallLog(Context context, Tools tools, String number) {
try {
tools.deleteFile("pcStatus.txt");
while (!tools.readFile("pcStatus.txt").equals("id=" + number)) {
Log.w("General Functions", "pcStatus.txt not found");
Thread.sleep(1000);
}
tools.deleteFile("status.txt");
Log.i("Call Log Test (" + number + ")", "Number to call: " + number);
Intent call = new Intent(Intent.ACTION_CALL);
call.setData(Uri.parse("tel:" + number));
context.startActivity(call);
tools.writeFile("status.txt", "endCall", false);
...
工具.java
public void writeFile(String fileName, String content, boolean append) {
File file = new File(context.getFilesDir(), fileName);
try {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
fos.write(content.getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
Log.i("Write File", "File: " + file.getAbsoluteFile() + "\nwritten successfully with data: " + content);
}
我的这个辅助类可以帮助您处理应用程序内部文件:
import android.content.Context;
import android.graphics.Bitmap;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
/**
* <b style="color: red;">This class is designed to work with Android 33.</b>
* <br>
* The private app internal storage files are located in the directory <b><code>getFilesDir()</code></b>.
* <br>
* <b>Alle files are stored and loaded in UTF-8.</b>
*
* @author David Weber
*/
public class AppInternalStorageHelper {
/**
* Checks if a file exists in the <b>app internal storage</b>.
*
* @return True if the file exists.
*/
public static boolean fileExists(
Context context,
String filename) {
return new File(context.getFilesDir(), filename).exists();
}
/**
* Gets the path of the file with the given file name in the <b>app internal storage</b>.
*
* @return The file path of the file as String if the file exists, otherwise null.
*/
public static String getPathOfFile(
Context context,
String filename) {
File file = new File(context.getFilesDir(), filename);
return file.exists() ? file.getPath() : null;
}
/**
* Creates and writes a file into the <b>app internal storage</b>.
*
* @return The created file.
*/
public static File createFile(
Context context,
String filename,
String fileContentAsString,
boolean overwriteExistingFile)
throws IOException {
File file = new File(context.getFilesDir(), filename);
if (overwriteExistingFile) {
Files.deleteIfExists(file.toPath());
}
return Files.write(file.toPath(), fileContentAsString.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE).toFile();
}
/**
* Creates and writes a file into the <b>app internal storage</b>.
*/
public static void createFile(
Context context,
String filename,
Bitmap fileContentAsBitmap,
Bitmap.CompressFormat fileFormat)
throws IOException {
File file = new File(context.getFilesDir(), filename);
OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
fileContentAsBitmap.compress(fileFormat, 100, os);
os.close();
}
/**
* Reads the content of a file from the <b>app internal storage</b> into bytes.
*/
public static byte[] readFileToBytes(
Context context,
String filename)
throws IOException {
File file = new File(context.getFilesDir(), filename);
return Files.readAllBytes(file.toPath());
}
/**
* Reads the content of a file from the <b>app internal storage</b> into a <code>String</code>.
*/
public static String readFileToString(
Context context,
String filename)
throws IOException {
return new String(readFileToBytes(context, filename), StandardCharsets.UTF_8);
}
/**
* Reads the content of a file from the <b>app internal storage</b> into a <code>List</code> of lines.
*/
public static List<String> readFileToLines(
Context context,
String filename)
throws IOException {
File file = new File(context.getFilesDir(), filename);
return Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
}
/**
* Deletes all files in the complete <b>app internal storage</b> whose file names begin with the given prefix.
*/
public static void deleteFilesWithPrefix(
Context context,
String filePrefix) {
ArrayList<File> filesToDelete = new ArrayList<>(AppInternalStorageHelper.findFilesWithPrefix(
context.getFilesDir(),
filePrefix));
for (File file : filesToDelete) {
//noinspection ResultOfMethodCallIgnored
file.delete();
}
}
/**
* Finds all files in the complete <b>app internal storage</b> whose file names begin with the given prefix.
*/
public static ArrayList<File> findFilesWithPrefix(
File dir,
String filePrefix) {
ArrayList<File> filesToReturn = new ArrayList<>();
File[] listedFiles = dir.listFiles();
if (listedFiles != null) {
for (File listedFile : listedFiles) {
if (listedFile.isDirectory()) {
findFilesWithPrefix(listedFile, filePrefix);
} else {
if (listedFile.getName().startsWith(filePrefix)) {
filesToReturn.add(listedFile);
}
}
}
}
return filesToReturn;
}
}
刚刚意识到删除应用程序特定的files文件夹可以解决问题:
/data/user/0/<package_name>/files/