精华内容
下载资源
问答
  • 如果您在API级别23或更高级别上运行应用程序,则必须在运行时请求权限.请求许可:String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};requestPermissions(permissions, WRITE_REQUEST_CODE);...

    如果您在API级别23或更高级别上运行应用程序,则必须在运行时请求权限.

    请求许可:

    String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};

    requestPermissions(permissions, WRITE_REQUEST_CODE);

    然后处理结果:

    @Override

    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {

    switch (requestCode) {

    case WRITE_REQUEST_CODE:

    if(grantResults[0] == PackageManager.PERMISSION_GRANTED){

    //Granted.

    }

    else{

    //Denied.

    }

    break;

    }

    }

    展开全文
  • File存储(内部存储)一旦程序在设备安装后,data/data/包名/ 即为内部存储空间,对外保密。Context提供了2个方法来打开输入、输出流FileInputStream openFileInput(String name)FileOutputStream openFileOutput...

    File存储(内部存储)一旦程序在设备安装后,data/data/包名/ 即为内部存储空间,对外保密。

    Context提供了2个方法来打开输入、输出流

    FileInputStream openFileInput(String name)

    FileOutputStream openFileOutput(String name, int mode)

    public class MainActivity extends Activity {

    private TextView show;

    private EditText et;

    private String filename = "test";

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    show = (TextView) findViewById(R.id.show);

    et = (EditText) findViewById(R.id.et);

    findViewById(R.id.write).setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View v) {

    try {

    FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE);

    //FileOutputStream是字节流,如果是写文本的话,需要进一步把FileOutputStream包装 UTF-8是编码

    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");

    //写

    osw.write(et.getText().toString());

    osw.flush();

    fos.flush();

    osw.close();

    fos.close();

    } catch (FileNotFoundException e) {

    e.printStackTrace();

    } catch (UnsupportedEncodingException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    });

    findViewById(R.id.read).setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View v) {

    try {

    FileInputStream fis = openFileInput(filename);

    //当输入输出都指定字符集编码的时候,就不会出现乱码的情况

    InputStreamReader isr = new InputStreamReader(fis, "UTF-8");

    //获取文件的可用长度,构建一个字符数组

    char[] input = new char[fis.available()];

    isr.read(input);

    isr.close();

    fis.close();

    String readed = new String(input);

    show.setText(readed);

    } catch (FileNotFoundException e) {

    e.printStackTrace();

    } catch (UnsupportedEncodingException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    });

    }

    }

    data/data/packagename/files/test就是我们写入的文件。

    SD存储(外部存储)mnt/sdcard 目录就是SD卡的挂载点(只是一个指向)。

    storage/sdcard: 真正的SD卡操作目录。

    一、文件下载Android开发中,有时需要从网上下载一些资源以供用户使用,Android API中已经提供了很多直接可以用的类供大家使用,一般文件下载需要通过三个步骤:

    1.创建一个HttpURLConnection对象

    // 创建一个URL对象,该对象包含一个IP地址,urlStr指的是网络IP地址

    url = new URL(urlStr);

    // 通过URL对象,来创建一个HttpURLConnection对象

    HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();

    2.获得一个InputStream对象

    InputStream input = urlConn.getInputStream();

    3.设置访问网络的权限

    //在AndroidManifest.xml配置文件中加入权限信息

    二、访问并写入SD卡1.判断手机上是否插入SD卡,且应用程序具有读写权限

    Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);

    2.得到当前SD卡的目录

    Environment.getExternalStorageDirectory();

    3.在访问SD卡前还必须在配置文件中设置权限,这样才可以最SD卡进行存取操作

    以下是一个对SD操作经常用到的封装类,以后如果需要对SD卡操作,直接可以拿过来用

    public class FileUtils {

    private String SDPATH;

    public String getSDPATH(){

    return SDPATH;

    }

    //构造函数,得到SD卡的目录,这行函数得到的目录名其实是叫"/SDCARD"

    public FileUtils() {

    SDPATH = Environment.getExternalStorageDirectory() +"/";

    }

    //在SD卡上创建文件

    public File createSDFile(String fileName) throws IOException{

    File file = new File(SDPATH + fileName);

    file.createNewFile();

    return file;

    }

    //在SD卡上创建目录

    public File createSDDir(String dirName){

    File dir = new File(SDPATH + dirName);

    dir.mkdir();

    return dir;

    }

    //判断SD卡上的文件夹是否存在

    public boolean isFileExist(String fileName){

    File file = new File(SDPATH + fileName);

    return file.exists();

    }

    //将一个InputStream里面的数据写入到SD卡中

    //将input写到path这个目录中的fileName文件上

    public File write2SDFromInput(String path, String fileName, InputStream input){

    File file = null;

    OutputStream output = null;

    try{

    createSDDir(path);

    file = createSDFile(path + fileName);

    //FileInputStream是读取数据,FileOutputStream是写入数据,写入到file这个文件上去

    output = new FileOutputStream(file);

    byte buffer [] = new byte[4 * 1024];

    while((input.read(buffer)) != -1){

    output.write(buffer);

    }

    output.flush();

    }

    catch(Exception e){

    e.printStackTrace();

    }

    finally{

    try{

    output.close();

    }

    catch(Exception e){

    e.printStackTrace();

    }

    }

    return file;

    }

    }

    展开全文
  • Android应用开发中,常使用Environment类去获取外部存储目录,在访问外部存储之前一定要先判断外部存储是否已经是可使用(已挂载&可使用)状态,并且需要在AndroidManifest.xml文件中添加外部存储读和写的权限 ...

    在这里插入图片描述
    Android应用开发中,常使用Environment类去获取外部存储目录,在访问外部存储之前一定要先判断外部存储是否已经是可使用(已挂载&可使用)状态,并且需要在AndroidManifest.xml文件中添加外部存储读和写的权限
    Environment类中提供了几个静态常量用于标识外部存储的状态,这些状态都是String类型

    MEDIA_BAD_REMOVAL 在没有挂载前存储媒体已经被移除。 MEDIA_CHECKING 正在检查存储媒体。
    MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读/写。 MEDIA_MOUNTED_READ_ONLY
    存储媒体已经挂载,挂载点只读。 MEDIA_NOFS 存储媒体是空白或是不支持的文件系统。 MEDIA_REMOVED 存储媒体被移除。
    MEDIA_SHARED 存储媒体正在通过USB共享。 MEDIA_UNMOUNTABLE 存储媒体无法挂载。
    MEDIA_UNMOUNTED 存储媒体没有挂载。

    可以通过静态方法getExternalStorageState()
    来获取外部存储的状态,如果程序需要在外部存储里面读写数据,
    必须要先判断:

    if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) 
    || !Environment.isExternalStorageRemovable());
    

    下面这篇文章写得外部存储的注意很全面,有很大的参考价值
    https://blog.csdn.net/FDGFGFDGFD/article/details/80434520

    如果在Android6.0(API:23)以下的版本中申请权限只需要AndroidMainfest文件中中申请权限就行,只需要这样写就行了

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myapplication">
    
    <!--    声明权限-->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE "/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
    
            <activity android:name=".ActivityExample">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="cn.itcast.start_activity" />
    <!--                当设置为LAUNCHER的时候,应用默认打开的界面-->
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <!--        配置Activity-->
            <!---->
            <activity android:name=".SecondActivity"></activity>
        </application>
    </manifest>
    

    上面不难看出,在manifest></mainfest>中直接添加的读取和写入的权限

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

    安卓6.0以上的版本怎么办,就需要动态申请权限了
    下面添加了一个显示跳转与隐式跳转的两种方式,是activity组件的知识,不必在意在此处

    package com.example.myapplication;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.OutputStreamWriter;
    
    public class ActivityExample extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_example);
            findViewById(R.id.start).setOnClickListener(this);
            findViewById(R.id.start).setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
    
            switch (v.getId()){
                case R.id.start:    //显示意图
                    Intent intent = new Intent(ActivityExample.this,MainActivity.class);
                    startActivity(intent);
                    break;
                case  R.id.start2:   //隐示意图
                    Intent intent1 = new Intent();
                    intent1.setAction("cn.itcast.start_activity");
                    startActivity(intent1);
                    break;
    
            }
        }
    }
    

    下面是自己画的界面,额,有点丑
    在这里插入图片描述
    实现代码:(采用的ConstraintLayout线性布局)

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:gravity="center">
    
        <CheckBox
            android:id="@+id/isAutoLogin"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="取消用户名"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.948"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.553" />
    
        <CheckBox
            android:id="@+id/isRememberUsername"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="记住用户名"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.572"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.553" />
    
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码:"
            android:textSize="24sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.186"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.449" />
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="用户名:"
            android:textSize="24sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.185"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.352" />
    
        <EditText
            android:id="@+id/password"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPassword"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.317"
            app:layout_constraintStart_toEndOf="@+id/textView2"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.457" />
    
        <EditText
            android:id="@+id/usename"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPersonName"
            android:text="Name"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.022"
            app:layout_constraintStart_toEndOf="@+id/textView"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.358" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="注册"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.746"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.736" />
    
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="登录"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.343"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.736" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    下面就是实现动态实现申请权限的方法:(单独一个文件)

    package com.example.myapplication;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.content.ContextCompat;
    
    import android.Manifest;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    
    
    public class MainActivity extends AppCompatActivity {
        //自定义文本、按钮、多选框的变量
        private EditText usename;
        private EditText password;
        private Button button;
        private Button button2;
        private CheckBox isRememberUsername;
        private CheckBox isAutoLogin;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            //下面的是新建程序自带的,实现父类中的onCreate方法
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //获取R文件的各种控件赋值给上面的控件
            //因为上面定义变量为成员变量,所以此处不必写类名
            //定义成员变量的目的是因为在在此文件下都可以私用
            usename = findViewById(R.id.usename);
            password = findViewById(R.id.password);
            button = findViewById(R.id.button2);
            button2 = findViewById(R.id.button);
            isRememberUsername = findViewById(R.id.isRememberUsername);
            isAutoLogin = findViewById(R.id.isAutoLogin);
    
            button2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    //                这里是内部存储,不需要申请权限
    
                    这里是开启Activity跳转的写法
    //                  采用的intent类进行开启的
                       // 参数一:Activity未跳转的界面
                       // 参数二:Activity将要跳转的界面
    //                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
    //                startActivity(intent);
    
                    文件读取,采用File流与getFilesDir()方法打开将要存储的文件
    //                File fileDir = getFilesDir();
                    //给文件起个名字login.data
    //                File destFile = new File(fileDir,"login.data");
    //                try {
    //                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destFile)));
                        //这里需要用包装类的valueOf()方法来进行转化,因为有的输入账号和密码是数字,需要转换为字符串
    //                    writer.write(String.valueOf(usename));
                        //这里需要不断地刷新换行,一行一行的读取
    //                    writer.newLine();
    //
    //                    writer.write(String.valueOf(password));
    //                    writer.newLine();
    //
    //                    writer.write(String.valueOf(isRememberUsername));
    //                    writer.newLine();
    //
    //                    writer.write(String.valueOf(isAutoLogin));
    //
    //                    writer.newLine();
                        //这里需要刷新一下保证全部读取成功
    //                    writer.flush();
                        //严格的编码需要关闭流
    //
    //                    Log.d("TEST","操作成功");
    //
    //                } catch (Exception e) {
    //                    Log.d("TEST",e.getMessage());
    //                    e.printStackTrace();
    //                }
    
    
                    //检查是否有写入存储卡的权限
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        //全部所需要的权限的数组,这里只添加了一个写入权限 
                        String[] permissions = {
                                Manifest.permission.WRITE_EXTERNAL_STORAGE
                        };
    
                        //用来表示,是否用有全部的权限,是为true,不是为false
                        boolean granted = true;
                        //对一个权限进行验证,for-Each循环
                        for (String permission : permissions) {
                            if (ContextCompat.checkSelfPermission(view.getContext(), permission) != PackageManager.PERMISSION_DENIED) {
                                    granted = false;
                                    break;
                            }
                        }
                        //编写两个方法,在下面,有权限就是直接写入,没有权限再
                        //验证是否拥有权限
                        if (granted) {
                            //存储用户登录信息
                            saveUserLogin();
                        } else {
                            //申请权限
                            requestPermissions(permissions, 0xA1);
                        }
                    } else {
                        //存储用户登录信息
                        saveUserLogin();
                    }
    
    
                }
            });
            //为登录设置一事件监听的提示
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    isRememberUsername.setChecked(false);
                    isAutoLogin.setChecked(false);
                    usename.setText("");
                    password.setText("");
                    Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                }
            });
    
    //        加载上次保存的信息
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("login.data")));
                String un = reader.readLine();
                String pw = reader.readLine();
    
            } catch (Exception e) {
                Log.d("TEST", e.getMessage());
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            //对应上面申请外部存储器的权限
            if (requestCode == 0xA1) {
                boolean granted = true;
                for (int result : grantResults) {
                    if (result != PackageManager.PERMISSION_DENIED) {
                        granted = false;
                        break;
                    }
                }
    
                if (granted) {
                    //确定获取了权限则进行写入
                    saveUserLogin();
                } else {
                    Toast.makeText(MainActivity.this, "未能能获取权限,不能进行此操作", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
        private void saveUserLogin() {
            //登录信息存储在外部存储器中
            if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_BAD_REMOVAL)) {
                File root = Environment.getExternalStorageDirectory();
                Log.d("TEST", root.getAbsolutePath());
                Log.d("TEST", "外部存储可用");
            } else {
                Log.d("TEST", "外部存储不可用");
            }
        }
    }
    
    展开全文
  • 对于您要与其他应用共享或允许用户使用计算机访问的文件,将其存储在外部存储上是很好的选择。 外部存储通常是通过可移动设备(例如 SD 卡)来提供的。Android 使用路径(例如 /sdcard)来表示这些设备。 在您请求...

    将文件保存到外部存储

    对于您要与其他应用共享或允许用户使用计算机访问的文件,将其存储在外部存储上是很好的选择。

    外部存储通常是通过可移动设备(例如 SD 卡)来提供的。Android 使用路径(例如 /sdcard)来表示这些设备。

    在您请求存储权限并确认存储可用后,可以保存以下类型的文件:

    公开文件:应可供其他应用和用户自由访问的文件。在用户卸载您的应用后,这些文件应该仍然可供用户使用。例如,您的应用拍摄的照片应保存为公开文件。
    私有文件:存储在特定于应用的目录中的文件(使用 Context.getExternalFilesDir() 来访问)。这些文件在用户卸载您的应用时会被清除。尽管这些文件在技术上可被用户和其他应用访问(因为它们存储在外部存储上),但它们不能为应用之外的用户提供价值。可以使用此目录来存储您不想与其他应用共享的文件。
    注意:如果用户移除了外部存储设备(例如 SD 卡)或断开其连接,则存储在外部存储上的文件可能会变得不可用。如果您的应用功能依赖于这些文件,则应将文件写入内部存储。
    本指南介绍如何管理存储在设备的外部存储设备上的文件。要了解如何使用内部存储中的文件,请参阅有关如何管理内部存储中的文件的指南。

    设置虚拟外部存储设备
    在没有可移动外部存储的设备上,可使用以下命令启用虚拟磁盘进行测试:

        adb shell sm set-virtual-disk true
    

    请求外部存储权限
    Android 包含以下访问外部存储中的文件的权限:
    READ_EXTERNAL_STORAGE
    允许应用访问外部存储设备中的文件。
    WRITE_EXTERNAL_STORAGE
    允许应用在外部存储设备中写入和修改文件。拥有此权限的应用也会自动获得 READ_EXTERNAL_STORAGE 权限。
    从 Android 4.4(API 级别 19)开始,在特定于应用的目录中读取或写入文件不再需要任何与存储相关的权限。因此,如果您的应用支持 Android 4.3(API 级别 18)及更低版本,并且您只想访问特定于应用的目录,则应添加 maxSdkVersion 属性,声明仅在较低版本的 Android 上请求权限:

        <manifest ...>
            <!-- If you need to modify files in external storage, request
                 WRITE_EXTERNAL_STORAGE instead. -->
            <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                             android:maxSdkVersion="18" />
        </manifest>
    

    注意:如果您的应用使用分区存储,则除非您的应用需要访问其他应用创建的文件,否则您将无需声明任何与存储相关的权限。
    验证外部存储是否可用
    由于外部存储可能会不可用(比如,当用户将存储安装到另一台机器或移除了提供外部存储的 SD 卡时),因此在访问之前,您应该始终先确认相应的卷可用。您可以通过调用 getExternalStorageState() 来查询外部存储的状态。如果返回的状态为 MEDIA_MOUNTED,则可以读取和写入文件。如果返回的是 MEDIA_MOUNTED_READ_ONLY,则只能读取文件。

    例如,以下方法可用于确定存储的可用性:

    KOTLIN

        /* Checks if external storage is available for read and write */
        fun isExternalStorageWritable(): Boolean {
            return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
        }
    
        /* Checks if external storage is available to at least read */
        fun isExternalStorageReadable(): Boolean {
             return Environment.getExternalStorageState() in
                setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
        }
        
    

    JAVA

        /* Checks if external storage is available for read and write */
        public boolean isExternalStorageWritable() {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                return true;
            }
            return false;
        }
    
        /* Checks if external storage is available to at least read */
        public boolean isExternalStorageReadable() {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state) ||
                Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
                return true;
            }
            return false;
        }
        
    

    保存到公开目录
    如果要将文件保存到其他应用可以访问的外部存储上,请使用以下 API 之一:

    如果要保存照片、音频文件或视频剪辑,请使用 MediaStore API。
    如果要保存任何其他文件(如 PDF 文档),请使用 ACTION_CREATE_DOCUMENT intent,这是存储访问框架的一部分。
    如果您不希望媒体扫描程序发现您的文件,请在特定于应用的目录中添加名为 .nomedia 的空文件(请注意文件名中的句点前缀)。这可以防止媒体扫描程序读取您的媒体文件并通过 MediaStore API 将它们提供给其他应用。

    保存到私有目录
    如果您想将应用专用文件保存在外部存储上,可以通过调用 getExternalFilesDir() 并传入指明您想要的目录类型的名称来获取特定于应用的目录。通过这种方式创建的每个目录都会被添加到一个父目录中,该目录包含了应用的所有外部存储文件,当用户卸载应用时,系统会清除这些文件。

    以下代码段展示了如何为单个相册创建目录:

    KOTLIN

        fun getPrivateAlbumStorageDir(context: Context, albumName: String): File? {
            // Get the directory for the app's private pictures directory.
            val file = File(context.getExternalFilesDir(
                    Environment.DIRECTORY_PICTURES), albumName)
            if (!file?.mkdirs()) {
                Log.e(LOG_TAG, "Directory not created")
            }
            return file
        }
        
    

    JAVA

        public File getPrivateAlbumStorageDir(Context context, String albumName) {
            // Get the directory for the app's private pictures directory.
            File file = new File(context.getExternalFilesDir(
                    Environment.DIRECTORY_PICTURES), albumName);
            if (!file.mkdirs()) {
                Log.e(LOG_TAG, "Directory not created");
            }
            return file;
        }
    

    请务必使用由 DIRECTORY_PICTURES 这类 API 常量提供的目录名称。这些目录名称可确保系统正确地处理这些文件。例如,保存在 DIRECTORY_RINGTONES 中的文件会被系统媒体扫描程序归类为铃声,而不是音乐。

    如果没有适合您文件的预定义子目录名称,您可以调用 getExternalFilesDir() 并传入 null。这会返回应用在外部存储上的专用目录的根目录。

    注意:getExternalFilesDir() 创建的目录在用户卸载您的应用时会被清除。如果您保存的文件需在用户卸载您的应用后继续保持可用(例如,当用户需要保留您的应用拍摄的照片时),则应将文件保存到公开目录中。
    在多个存储位置之间选择
    有时,分配内部存储分区作为外部存储的设备也会提供 SD 卡插槽。这意味着该设备会有两个不同的外部存储目录,因此在将“私有”文件写入外部存储时,需要选择使用哪个目录。

    从 Android 4.4(API 级别 19)开始,您可以通过调用 getExternalFilesDirs() 来访问这两个位置,这会返回一个 File 数组,其中包含了每个存储位置的条目。数组中的第一个条目被视为主要外部存储,除非该位置已满或不可用,否则应该一律使用该位置。

    如果您的应用支持 Android 4.3 及更低版本,则应使用支持库的静态方法 ContextCompat.getExternalFilesDirs()。这始终会返回一个 File 数组,但如果设备搭载的是 Android 4.3 及更低版本,数组中将仅包含主要外部存储的条目。(如果有第二个存储位置,您将无法在 Android 4.3 及更低版本上访问它。)

    唯一卷名称
    面向 Android 10(API 级别 29)或更高版本的应用可以访问系统分配给每个外部存储设备的唯一名称。此命名系统可帮助您高效地整理内容并将内容编入索引,还可让您控制新内容的存储位置。

    主要共享存储设备始终名为 VOLUME_EXTERNAL_PRIMARY。您可以通过调用 MediaStore.getExternalVolumeNames() 来发现其他卷。

    要查询、插入、更新或删除特定卷,请将卷名称传入 MediaStore API 中提供的任何 getContentUri() 方法,如以下代码段中所示:

        // Assumes that the storage device of interest is the 2nd one
        // that your app recognizes.
        val volumeNames = MediaStore.getExternalVolumeNames(context)
        val selectedVolumeName = volumeNames[1]
        val collection = MediaStore.Audio.Media.getContentUri(selectedVolumeName)
        // ... Use a ContentResolver to add items to the returned media collection.
    

    注意:从 Android 10 开始,StorageVolume 类中的 createAccessIntent() 方法已被弃用,因此您不应再使用此方法浏览外部存储设备。如果您这样做,在搭载 Android 10 或更高版本的设备上访问您的应用的用户,将无法在您的应用中查看保存在外部存储中的文件。

    展开全文
  • 写数据到外部系统,需要建立一个数据连接对象(例如TCP连接到远程的服务器),使用它将数据发送到外部存储系统。为此开发者可能会在Driver中尝试创建一个连接,然后在worker中使用它来保存记录到外部数据。代码如下...
  • android,内部存储,外部存储,权限理解

    千次阅读 2017-07-26 09:59:43
    这是我的一些理解:首先android 的文件存储有两大类,第一个是Context (内部存储),第二个是Environment类 (外部存储) ----------------------------------内部存储----START---------------------------------------...
  • * 当前应用程序的targetSdkVersion小于23(为22),系统会默认其尚未适配新的运行时权限机制,安装后将和以前一样不受影响:即用户在安装应用程序的时候默认允许所有被申明的权限 */ private void export() {...
  • 所有的Android设备都支持保存文件到外部存储外部存储可能是可移除的存储介质(例如SD卡)或者手机内部介质,保存到外部存储的文件是全局可读取文件,用户可以修改这些文件。 使用场景 (1)你想将你的应用的...
  • python字典存储写入

    千次阅读 2020-12-18 12:10:18
    文件的基本操作 文件是指存储外部介质(如磁盘)上数据的集合.文件的操作流程为: 打开文件(读方式\写方式)->读写文件(read\readl... 文章 小珞珞 2014-10-08 937浏览量 数据库必知词汇:Redis Redis(全称:Remote ...
  • 文件存储前言文件存储内存内部存储外部存储内部存储操作API读写操作外部存储操作公共目录私有目录私有文件私有缓存 前言 众所周知,数据存储在每个应用中都会用到,那所用到的技术应该怎么选呢,这里Android给...
  • Android 外部存储权限分析

    万次阅读 多人点赞 2014-05-24 19:56:26
    不知道你有么有发现,KitKat之后的版本不再支持用户对外置SDcard(Secondary Storage)的写入等操作。如果用户想要 将文件等copy到手机中,则只能存储到内部存储器中,而无法存储到外置sdcard中,而且无法创建新的...
  • --外部存储的写权限--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!--外部存储的读权限--><uses-permission android:name="android.permission.READ_...
  • 输出操作指定了对流数据经转化操作得到的数据所要执行的操作(例如把结果推入外部数据库或输出到屏幕上)。与RDD中的惰性求值类似,如果一个DStream及其派生出的DStream都没有被执行输出操作,那么这些DStream就都不会...
  • 各位大神,如题 :代码...请问还需要什么其他配置才能在外部存储中生成文件吗? 我其实希望生成excel 文件 ,使用 jxl.jar 中的方法: workbook.write(); workbook.close(); 也是不行,求各位过来人指点 ,谢谢了
  • HDFS跨外部存储系统的多层级存储

    千次阅读 2017-04-03 15:14:06
    在一些更大规模的公司,已经将大数据与云联系在了一起了,举个例子,我们将数据存储在HDFS内,然后在定期同步到云上,相当于云端存储的数据是一个back store。这样做的一个好处是防止本地集群的数据遭到意外的破坏或...
  • Android外部存储

    2016-10-14 20:06:09
    /** * 外部存储 * 1.外部存储设备不见得总是可用 使用外部存储时需要判断设备的可用性 * 2.外部存储中的文件设备中app都可以访问 * 3.外部存储的适用情况: ... * app卸载时私有外部存储的文件
  • 很多时候我们开发的软件需要对处理后的数据进行存储,以供再次访问。Android为数据存储提供了如下几种方式: 1、文件 2、SharedPreferences(偏好参数) 3、SQLite数据库 4、内容提供者(Content provider) 5、...
  • 1要对外部的内存空间进行增删和写入的话,需要加入两个权限代码如下: 第一个是允许挂载和反挂载文件系统可移动存储; 第二个是模拟器中sdcard中创建文件夹的权限 2每次使用外部存储之前都是对检查存储介质是否...
  • IT之家获悉,新功能特性包括支持设置每个应用是否允许访问手机相册存储目录和社交应用信息存储目录中的文件内容;「读取与写入手机存储」权限增加访问内容管理,可在「读取与写入手机存储」授权弹窗和权限管理页面...
  • Android9.0外置sd卡无法写入的问题

    千次阅读 2019-04-29 14:06:53
    记录:https://blog.csdn.net/qq_36467463/article/details/88691726
  • 文章目录授权访问利用redis写入webshell任务计划反弹Shellssh-keygen 公钥登录服务器利用主从复制RCEwindowsSSRF安全设置 REmote DIctionary Server(Redis) 是一个 key-value 存储系统,是跨平台的非关系型(Nosql...
  • 原文:Android6.0权限适配之WRITE_EXTERNAL_STORAGE(SD卡写入) 前一篇博客中介绍了Android6.0运行时权限简介,最近遇到这么一个情况,就是一个App以前都是在SD卡根目录直接新建了一个XXX/image/目录,来...
  • 转载自:https://blog.csdn.net/daniel80110_1020/article/details/55504833Android应用开发中,常使用Environment类去获取外部存储目录,在访问外部存储之前一定要先判断外部存储是否已经是可使用(已挂载&...
  • Android 外部存储 内部存储
  • 云计算设计模式(八)——外部配置存储模式 移动配置信息从应用部署包到一个集中位置。这个模式可以提供机会,以便管理和配置数据的控制,以及用于跨应用程序和应用程序实例共享的配置数据。
  • 红米手机怎么把软件移到sd卡

    千次阅读 2021-09-12 17:05:15
    将软件移到sd卡需要先进入开发者选项,打开强制允许将应用写入外部存储设备功能,再通过第三方软件将软件移到sd卡即可,操作方法如下: 1、首先打开手机设置,选择我的设备。 2、找到全部参数并点开,多次点击...
  • Android 外部SD卡/U盘无法写入解决方法(需要root) 2013-11-29 14:20 24109人阅读 评论(0) 收藏 举报 分类: Android平板电脑(40) 版权声明:本文为博主原创文章,未经博主允许...
  • 1. 文件存储数据 [也就是通常说的SD卡中]  2. 使用SharedPreferences存储数据 3. SQLite数据库存储数据 4. 使用ContentProvider存储数据 5. 网络存储数据 [可以把本地的数据存储在网络的服务端]   在我们...
  • postgres_fdw模块提供了外部数据包装器postgres_fdw,它可以被用来访问存储外部PostgreSQL服务器中的数据。 这个模块提供的功能大体上覆盖了较老的dblink模块的功能。但是postgres_fdw提供了更透明且更兼容标准的...
  • 这些名称在 Android 早期产生,当时大多数设备都提供内置的非易失性内存(内部存储),以及移动存储介质,比如micro SD 卡(外部存储)。一些设备将永久性存储空间划分为“内部”和“外部”分区,即便没有移动存储...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 114,440
精华内容 45,776
关键字:

当未允许写入外部存储