Android应用无法读取外部存储文件

时间:2016-07-06 14:23:53

标签: android file

我正在创建一个仅供私人使用的应用......它不是那么重要,尊重你的时间:P

我想要的是一个从数据库中读取并播放声音的应用程序。我已经创建了数据库,我可以从res / raw文件夹中播放声音。但是,有数千个文件可供播放,一些新文件将成为应用程序的一部分,其他文件将在未来删除。所以,添加一个简单的文件让我每次下载整个应用程序(~1 GB)(或者我错了?)。相反,我想到了读取Excel文件然后从SD卡播放声音。但据我所知,我无法做到:

  

不允许应用程序向外部存储写入(删除,修改...)   除了特定于包的目录。

我将文件放入 / storage / emulated / 0 / Android / data / my_package_folder / files 文件夹中。我读过很多主题,没有任何帮助。

Environment.MEDIA_MOUNTED.equals(extStorageState) //returns true
Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState) //returns false

我尝试了一些创建新文件对象或使用媒体播放器播放声音的方法(正如我之前说的那样,播放res / raw文件没有问题)但是文件。存在总是返回false或声音没有播放:

String filePath = getExternalFilesDir(null) + "/myfile.mp3"; //returns correct file path
File file = new File(filePath);

OR

File file = new File(getExternalFilesDir(null).getPath(), "myfile.mp3");

OR

MediaPlayer mp;
mp = MediaPlayer.create(this, Uri.parse(getExternalFilesDir(null).getPath() + "/myfile.mp3"));

minSdkVersion设置为19,因此我在Manifest中不需要该行:

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

我已经包含了这一行而没有任何改变:

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

我也试图用其他文件扩展名来做这件事。此外,here的解决方案没有帮助。我的手机是三星Galaxy Grand Prime(SM-G530FZ),Android v.5.0.2。请帮忙! :)

5 个答案:

答案 0 :(得分:4)

这是代码@Nisarg,不得不稍微清理一下:

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import java.io.File;

public class MainActivity extends AppCompatActivity implements OnClickListener {

Button readExcelButton;
static String TAG = "ExelLog";
MediaPlayer mpintro;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
        Toast.makeText(this, "Permission checking", Toast.LENGTH_SHORT).show();
        checkPermission();
    }

    readExcelButton = (Button) findViewById(R.id.readExcel);
    readExcelButton.setOnClickListener(this);

}

public void onClick(View v)
{
    switch (v.getId())
    {
        case R.id.readExcel:
            String filePath = getExternalFilesDir(null) + "/p0000.mp3";
            File file = new File(filePath);
            file.setReadable(true);
            file.setWritable(true);

            if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) {
                Toast.makeText(this, "Ext storage not available or read only", Toast.LENGTH_SHORT).show();
            }
            else {
                Toast.makeText(this, "Ext storage available", Toast.LENGTH_SHORT).show();
            }

            if (file.exists()){
                Toast.makeText(this, "File found", Toast.LENGTH_SHORT).show();
            }
            else {
                Toast.makeText(this, getExternalFilesDir(null) + "/p0000.mp3 - File not found", Toast.LENGTH_LONG).show();
            }

            break;
    }
}

private void checkPermission() {
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {//Can add more as per requirement

        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},
                123);

    } else {

    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 123: {

            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED)     {
                //Peform your task here if any
            } else {

                checkPermission();
            }
            return;
        }
    }
}

public static boolean isExternalStorageReadOnly() {
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
        return true;
    }
    return false;
}

public static boolean isExternalStorageAvailable() {
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
        return true;
    }
    return false;
}

}

答案 1 :(得分:1)

您还必须拥有READ_EXTERNAL_STORAGE权限;在外部存储方面,写入或读取是不够的,因为你必须同时使用

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

您还可以在declaration

中阅读有关外部数据撰写的更多信息

您无法阅读的原因是您没有添加该权限。一个好的规则是,如果您只需要阅读,则只能使用读取权限。但如果您需要编写,则需要写入和读取权限

修改

加载目录时,请尝试:

file.setReadable(true);
file.setWritable(true);

注意:值&#39;文件&#39;这里是针对目录,而不是每个单独的文件(尽管它也可以正常工作)

来自宣言:

  

此权限从API级别19开始强制执行。在API级别19之前,不会强制执行此权限,并且所有应用程序仍然可以从外部存储中读取。

如果我是正确的,那意味着API 19及以上的权限必须在那里,而不是在API 19之前

答案 2 :(得分:1)

如果你的targetSdk是23,那么你需要为marshmallow及以上设备检查这样的权限

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
    checkPermission();
}
else {
}


private void checkPermission() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {//Can add more as per requirement

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},
                    123);

        } else {

        }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                   String permissions[], int[] grantResults)   
   {
    switch (requestCode) {
        case 123: {


 if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED)     {
   //Peform your task here if any
    } else {

        checkPermission();
    }
        return;
    }
}
}

答案 3 :(得分:0)

 MyMediaPlayer=MediaPlayer.create(this,Uri.parse(String.valueOf(Uri.fromFile(f))));

在此MyMediaPlayerMediaPlayer,||ly f的对象是文件的对象 在这里我们首先转换为uri然后转换为uri为string,最后转换为uri。

我之所以这样做,是因为当我们采用我们选择的路径时,它需要/// 3times /,但它只需要2倍,这就是为什么我完成了这个转换,这有助于我采取所需的文件路径。

试试我的朋友。

答案 4 :(得分:0)

Android 9(API级别28)开始限制哪些应用程序可以使内部存储设备上的数据目录中的文件在世界范围内可供其他应用程序访问。面向Android 9或更高版本的应用程序无法使其数据目录中的文件可全球访问。有关更多信息,请检查此link

如果您将API级别定位为28级或更高,要解决问题,您只需在 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.your.application">

   <!-- These three tags -->
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
   <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/>

   <!-- Add the tag android:requestLegacyExternalStorage="true" in application -->
   <!-- Other tags has been omitted -->
   <application
      android:requestLegacyExternalStorage="true">
   </application>

</manifest>

现在,您可以检查自己是否能够读写:

File root = new File(Environment.getExternalStorageDirectory() + "/My app folder");

Log.d("Storage: can write", String.valueOf(root.canWrite()));
Log.d("Storage: can read", String.valueOf(root.canRead()));

两个日志的结果都应该为TRUE。