我有一个应用程序要将当前的SQLite数据库导出到设备的Internal storage Downloads文件夹。我收到以下错误。
java.io.FileNotFoundException: / storage / emulated / 0 / Download / Pipe_Tally:打开失败:EACCES (许可被拒绝)
我认为AndroidManifest.xml
文件中包含的用于读取和写入存储的正确权限。
这是AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.bigdaddy.pipelinepipetally">
<uses-feature android:name="android.hardware.camera2"
android:required="true"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<application
android:allowBackup="true"
android:debuggable="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="HardcodedDebugMode">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".TallyActivity2"
android:windowSoftInputMode="adjustResize">
</activity>
<activity
android:name=".JobAndDbActivity"
android:windowSoftInputMode="adjustResize">
</activity>
<activity
android:name=".ExistingTallyActivity"
android:windowSoftInputMode="adjustResize">
</activity>
<activity android:name=".ImageToFullscreen"
android:windowSoftInputMode="adjustResize">
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.bigdaddy.pipelinepipetally.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
</application>
</manifest>
以下是我尝试用于为内部设备存储中的/Downloads/
文件夹创建文件的方法:
public void backUpDatabase() {
/* Open your local db as the input stream */
DBHelper anotherDbHelper = null;
try {
try {
anotherDbHelper = new DBHelper(ExistingTallyActivity.this);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String path = null;
if (anotherDbHelper != null) {
path = String.valueOf(getApplicationContext().getDatabasePath(anotherDbHelper.getDatabaseName()));
Log.i(TAG, "backUpDatabase: 1" +path);
}
File dbFile = null;
if (path != null) {
dbFile = new File(path);
Log.i(TAG, "backUpDatabase: 2" + String.valueOf(dbFile));
}
FileInputStream fis = null;
try {
if (dbFile != null) {
fis = new FileInputStream(dbFile);
Log.i(TAG, "backUpDatabase: 3" + String.valueOf(dbFile));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String outFileName = (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()+ "/Pipe_Tally/");
Log.i(TAG, "backUpDatabase: 4"+ outFileName);
// Open the empty db as the output stream
OutputStream outputStream = null;
//FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(outFileName);
Log.i(TAG, "backUpDatabase: 5"+ outFileName);
Log.i(TAG, "backUpDatabase: 6"+ String.valueOf(outputStream));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// Transfer bytes from the input-file to the output-file
byte[] buffer = new byte[1024];
int length;
try {
if (fis != null) {
while ((length = fis.read(buffer)) > 0) {
try {
if (outputStream != null) {
outputStream.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
//Close the streams
try {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
以下是我用于在运行时检查正确权限的方法:
private boolean checkSdCardPermissions() {
/* Checking here if we already have permissions*/
if (ActivityCompat.checkSelfPermission(ExistingTallyActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(ExistingTallyActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { /* Added this for Write External Storage permissions */
/* Checking to see if we are equal to or at a higher version than Marshmallow */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/* System default popup box here to ask for permissions. */
ActivityCompat.requestPermissions(ExistingTallyActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
MY_PERMISSION_READ_EXTERNAL_STORAGE);
/* Added this today for trying to prompt for writing external storage*/
ActivityCompat.requestPermissions(ExistingTallyActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSION_WRITE_EXTERNAL_STORAGE);
}
return true;
} else {
return false;
}
}
这是onOptionsItemSelected()
方法,其中包含switch
来处理菜单和选择的内容。 case:R.id.menu_save_and_export:
我正在检查checkSdCardPermissions()
方法是否为真,然后调用backUpDatabase()
方法。
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
/*
When Tally New Pipe is selected from the Menu, it sends the user to the TallyActivity
page, all encapsulated in a runnable and passed to thread below.
*/
case R.id.menu_new_pipe:
class ToTallyActivityManager implements Runnable {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Intent intentToTallyActivity =
new Intent(ExistingTallyActivity.this, TallyActivity2.class);
startActivity(intentToTallyActivity); /* Heading to TallyActivity.*/
} /* run method ends here. */
} /* Runnable ends here. */
/* This thread takes care of the call to go to TallyActivity page from here.*/
mThreadToTallyActivity = new Thread(new ToTallyActivityManager());
mThreadToTallyActivity.start();
break;
/* When selected, sends the user to the MainActivity page. */
case R.id.menu_to_main:
Intent intentToMainActivity =
new Intent(ExistingTallyActivity.this, MainActivity.class);
startActivity(intentToMainActivity); // Heading to MainActivity
break;
/* When chosen allows the option to save and export the current DB.*/
case R.id.menu_save_and_export:
if (checkSdCardPermissions()) {
try {
backUpDatabase();
} catch (/*IOException*/ SQLException e) {
e.printStackTrace();
}
}
break;
/* When chosen from the menu, this kills the app completely. Has popup embedded.*/
default:
AlertHelperDialog.displayExitAlertDialog(ExistingTallyActivity.this);
} /* switch/case ends here */
return super.onOptionsItemSelected(menuItem);
} /* onOptionsItemSelected method ends here. */
我非常感谢您解决此问题的任何帮助或建议。谢谢。
答案 0 :(得分:0)
您在WRITE_EXTERNAL_STORAGE
权限上设置了WRITE_EXTERNAL_STORAGE
。如果您在使用SDK&gt;的手机上运行18该应用无法获得android:maxSdkVersion
的许可。因此,我建议您删除<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
属性。阅读documentation。
android:maxSdkVersion:应该为您的应用授予此权限的最高API级别。如果从某个API级别开始不再需要您的应用所需的权限,则设置此属性非常有用。
按如下方式更改,
compute angle for every point -- O(n)
sort point by angles -- O(n*lg(n))
for each pair -- O(n^2*lg(n))
if (B.x > A.x) && (B.y > A.y)
compute positions of C and D
compute angles of C and D
for C and D
if there is a pair of points with same angles and same positions
return true
return false