Android之本地数据存储(SharedPrederences、ExternalStorage、InternalStorage)


在这里插入图片描述

前4种为本地数据存储方式


一、SharedPreferences

1、特点:存储量小,时间持久

在这里插入图片描述

2、SharedPreferences操作模式

在这里插入图片描述
MODE_APPEND不能被使用,代码会报错,提示使用其他的模式
MODE_PRIVATE使用最多

3、获取SharedPreferences对象

3.1 Context.getSharedPreferences()

public SharedPreferences getSharedPreferences(String name, int mode)

参数1:name,用于指定SharedPreferences文件的名称。如果指定的文件不存在则会创建一个,该文件都是存放在data/data/包名/shared_prefs/ 目录下

参数2:mode,用于指定操作模式,目前只有MODE_PRIVATE这一种模式可选

3.2 Activity.getPreferences()

public SharedPreferences getPreferences(@Context.PreferencesMode int mode) {

和getSharedPreferences()方法很相似,只接收一个参数:操作模式,自动将当前活动的类名作为SharedPreferences的文件名

例如:
LoginActivity.xml

3.3 PreferenceManager.getDefaultSharedPreferences()

public static SharedPreferences getDefaultSharedPreferences(Context context)

静态方法。自动使用当前应用程序的包名作为前缀来命名SharedPerences文件

例如:
com.example.sharedpreferencedstudy2_preferences.xml


4、SharedPreferences的使用

具体代码:【创建StorageStudy工程】

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/share_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="SharePreference演示"
        android:onClick="operate"
        app:layout_constraintBottom_toTopOf="@id/external_btn"
        android:layout_margin="5dp"/>

    <Button
        android:id="@+id/external_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="外部存储演示"
        android:onClick="operate"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_margin="5dp"/>

    <Button
        android:id="@+id/internal_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="内部存储演示"
        android:onClick="operate"
        app:layout_constraintTop_toBottomOf="@id/external_btn"
        android:layout_margin="5dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

参考资料:Intent相关知识

public class MainActivity extends AppCompatActivity {

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

    public void operate(View v){
        Intent it=null;
        switch (v.getId()){
            case R.id.share_btn:
                it = new Intent(this,ShareActivity.class);
                break;
            case R.id.external_btn:
                it = new Intent(this,ExternalActivity.class);
                break;
            default:
                it = new Intent(this,InternalActivity.class);
                break;
        }
        startActivity(it);
    }
}

效果图:
在这里插入图片描述


SharedPreferences演示(ShareActivity)

activity_share.xml

<?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"
    tools:context=".ShareActivity"
    >

    <TextView
        android:id="@+id/textView7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:text="账号:"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@+id/guideline3"
        app:layout_constraintEnd_toStartOf="@+id/guideline5" />

    <!--    账号输入框-->
    <EditText
        android:id="@+id/acc_edt"
        android:layout_width="350dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline3"
        app:layout_constraintStart_toStartOf="@+id/guideline5" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:text="密码:"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@+id/guideline4"
        app:layout_constraintEnd_toStartOf="@+id/guideline5" />

    <!--    密码输入框-->
    <EditText
        android:id="@+id/pwd_edt"
        android:layout_width="350dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:inputType="textPassword"
        app:layout_constraintBottom_toTopOf="@+id/guideline4"
        app:layout_constraintStart_toStartOf="@+id/guideline5" />

    <!--    登录按钮-->
    <Button
        android:id="@+id/login_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:text="登录"
        app:layout_constraintTop_toTopOf="@+id/guideline4" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="93dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="179dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="88dp" />

</androidx.constraintlayout.widget.ConstraintLayout>
存储信息

四步:

①获取SharePreference对象(参数1:文件名,参数2:操作模式)
SharedPreferences share = getSharedPreferences("myshare", MODE_PRIVATE);
②获取Editor对象
SharedPreferences.Editor edt = share.edit();
③存储信息(把输入框的内容以key–value存储进去)
edt.putString("account", account);
edt.putString("pwd", pwd);
④执行提交操作
edt.commit();或者 edt.apply();

edt.commit();与edt.apply();的区别是什么

具体代码:

package com.example.storagestudy;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

/**
 * function:
 * Created by TMJ on 2020-02-22.
 */
public class ShareActivity extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share);

        /**
         * 初始化控件
         */
        final EditText accEdt=(EditText)findViewById(R.id.acc_edt);
        final EditText pwdEdt=(EditText)findViewById(R.id.pwd_edt);

        /**
         * 为登录按钮设置点击事件
         */
        findViewById(R.id.login_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //1、获取两个输入框(账号、密码输入框)的内容
                String account=accEdt.getText().toString();
                String pwd=pwdEdt.getText().toString();


                //2、验证(admin 123算成功)
                    if(account.equals("admin")&&pwd.equals("123")){
                        //2.1、存储信息到SharePreference中
                        //①获取SharePreference对象(参数1:文件名【本质上是一个xml文件】,参数2:操作模式)
                        SharedPreferences share=getSharedPreferences("myshare",MODE_PRIVATE);
                        //②获取Editor对象
                        SharedPreferences.Editor edt=share.edit();
                        //③存储信息(把输入框的内容以key--value存储进去)
                        edt.putString("account",account);
                        edt.putString("pwd",pwd);
                        //④执行提交操作
                        edt.commit();

                        Toast.makeText(ShareActivity.this,"登录成功",Toast.LENGTH_SHORT).show();

                    }else{
                        //2.2、验证失败,提示用户(账号或密码错误等等)
                        Toast.makeText(ShareActivity.this,"账号或密码错误",Toast.LENGTH_SHORT).show();
                    }
            }
        });
    }
}

效果图:
在这里插入图片描述

登录失败,不会生成;登录成功,检查到没有,会自行创建一个myshare.xml:
在这里插入图片描述

打开Device File Explorer --> data --> data --> 当前包名com.example.storagestudy --> 生成shared_prefs:myshare.xml
在这里插入图片描述

myshare.xml

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="account">admin</string>
    <string name="pwd">123</string>
</map>

读取信息

读取信息:下一次再进入此界面时,能出现已经配置好的信息(账号、密码)

三步
①获取SharePreference对象(参数1:,参数2:操作模式)因为myshare文件已经被创建了,所以在这里会直接打开
SharedPreferences share = getSharedPreferences("myshare", MODE_PRIVATE);
②根据key获取内容(参数1:key,参数2:当对应key不存在时,返回参数2的内容作为默认值)
String accStr = share.getString("account", ""); String pwdStr = share.getString("pwd", "");
③将上面读取出来的内容设置到相应的文本显示框
accEdt.setText(accStr);
pwdEdt.setText(pwdStr);

具体代码:

package com.example.storagestudy;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

/**
 * function:
 * Created by TMJ on 2020-02-22.
 */
public class ShareActivity extends AppCompatActivity {

    //后续会使用到这两个控件,故提取为全局变量
    private EditText accEdt;
    private EditText pwdEdt;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share);

        // 初始化控件
        accEdt = (EditText) findViewById(R.id.acc_edt);
        pwdEdt = (EditText) findViewById(R.id.pwd_edt);

        /**
         * SharePreference的读取
         */
        //2.1、存储信息到SharePreference中
        //①获取SharePreference对象(参数1:文件名【本质上是一个xml文件】,参数2:操作模式)因为myshare文件已经被创建了,所以在这里会直接打开
        SharedPreferences share = getSharedPreferences("myshare", MODE_PRIVATE);
        //②根据key获取内容(参数1:key,参数2:当对应key不存在时,返回参数2的内容作为默认值)
        String accStr = share.getString("account", "");
        String pwdStr = share.getString("pwd", "");

        //将上面读取出来的内容设置到相应的文本显示框
        accEdt.setText(accStr);
        pwdEdt.setText(pwdStr);

        /**
         * 为登录按钮设置点击事件
         */
        findViewById(R.id.login_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                ... ...
                
                }
            }
        });
    }
}

效果图:

再点进去时,出现之前配置好的信息(账号、密码)
在这里插入图片描述

将之前存储的信息全部清空
edt.clear();


二、 外部存储ExternalStorage

1、 概念

区分:
在这里插入图片描述
内存:设备的容量
内部存储:设备中一个实际存在的位置
外部存储:设备中一个比较特殊的位置,由于手机不同,位置也不一样,可能在storage/sdcard或者mnt/xxxx/0下


外部存储:
在这里插入图片描述

1、外部存储的位置可使用Environment.getExternalStorageDirectory().getAbsolutePath()获得

2、9大公有目录,以作用来命名(DCIM:存储照片,DOWNLOAD:下载文件,直接存储在外部存储的根目录下,需要申请权限

3、私有目录,Android/data/应用包名,只能被当前应用访问到

注意:

①在实际开发中不建议在内部存储中存储数据,因为容量很有限

②在实际开发中经常讲把数据存储到私有目录,便于系统维护,软件卸载了数据就删除了


2、 具体操作

activity_external.xml

<?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"
    tools:context=".ExternalActivity">

    <!--    代存储内容输入框-->
    <EditText
        android:id="@+id/info_edt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="22dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:gravity="left|top"
        android:hint="请输入待存储的内容..."
        android:maxLines="12"
        android:minLines="12"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!--    读取按钮-->
    <Button
        android:id="@+id/read_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:onClick="operate"
        android:text="读取"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/save_btn"
        app:layout_constraintTop_toTopOf="parent" />

    <!--    保存按钮-->
    <Button
        android:id="@+id/save_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:onClick="operate"
        android:text="保存"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!--    读取上面存储的内容-->
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="176dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

外部存储要申请权限

写入的权限,创建和删除文件的权限

AndroidManifest.xml

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

android.permission.MOUNT_UNMOUNT_FILESYSTEMS添加权限报错的两种解决方案

ExternalActivity(写入外部存储文件)

写入步骤
1、创建文件输出流(参数1:传入文件目录,参数2:表示是否可以追加内容)
FileOutputStream fos = new FileOutputStream(path, true);
2、获取输入框的内容
String str = infoEdt.getText().toString();
3、以字节流的方式写入内容(输入框的内容)
fos.write(str.getBytes());
4、关闭流
fos.close();

文件所在路径:

String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/imooc.txt";
Log.d(TAG,  path);

具体代码:

02-22 15:17:59.304 7048-7048/com.example.storagestudy D/ExternalActivity: /storage/sdcard/imooc.txt

package com.example.storagestudy;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * function:
 * Created by TMJ on 2020-02-22.
 */
public class ExternalActivity extends AppCompatActivity {

    private static final String TAG = "ExternalActivity";
    private EditText infoEdt;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_external);

        infoEdt = (EditText) findViewById(R.id.info_edt);
        TextView txt = (TextView) findViewById(R.id.textView);
    }

    /**
     * 在activity_external.xml布局文件中添加点击事件属性,来注册点击事件
     *
     * @param view
     */
    public void operate(View view) {

        //Environment.getExternalStorageDirectory():拿到根目录
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/imooc.txt";
        Log.d(TAG, "operate: " + path);

        //equals的话,内存卡存在
//        if (Environment.getExternalStorageState().equals("mounted"))

        switch (view.getId()) {

            /**
             * 按入保存按钮,文件不存在,创建一个文件;存在,直接打开进行操作
             */
            case R.id.save_btn:

                //创建一个文件
                File file = new File(path);
                try {
                    //如果不存在,创建一个新的
                    if (!file.exists()) {
                        file.createNewFile();
                    }
                    //有文件了,往里面输出内容
                    //创建文件输出流(参数1:传入文件目录,参数2:表示是否可以追加内容)
                    FileOutputStream fos = new FileOutputStream(path, true);
                    //获取输入框的内容
                    String str = infoEdt.getText().toString();
                    //以字节流的方式写入内容(输入框的内容)
                    fos.write(str.getBytes());
                    //关闭流
                    fos.close();


                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
            case R.id.read_btn:

                break;
        }
    }
}

效果图:

在文件目录下生成了imooc.txt文件
在这里插入图片描述
注意:模拟器只能输英文、数字和符号

其中内容为:

hello,imooc

安卓权限代表意思


ExternalActivity(读取外部存储文件)

读取步骤

1、创建文件输入流
FileInputStream fis = new FileInputStream(path);
2、创建字节数组
byte[] b = new byte[1024];
3、读取输入流内容(读取的内容存储在字节数组中),返回读取到的长度
int len= fis.read(b);
4、利用保存读取内容的字节数组,生成字符串
String str2=new String(b,0,len);
5、将内容显示在文本显示框(读文件是不需要申请权限的)
txt.setText(str2);
6、关闭流
fis.close();

public class ExternalActivity extends AppCompatActivity {

    ... ...

    /**
     * 在activity_external.xml布局文件中添加点击事件属性,来注册点击事件
     *
     * @param view
     */
    public void operate(View view) {

        ... ...

        switch (view.getId()) {

            ... ...
            
            case R.id.read_btn:

                try {
                    //创建文件输入流
                    FileInputStream fis = new FileInputStream(path);
                    //创建字节数组
                    byte[] b = new byte[1024];
                    //读取输入流内容(读取的内容存储在字节数组中),返回读取到的长度
                    int len= fis.read(b);
                    //利用保存读取内容的字节数组,生成字符串
                    String str2=new String(b,0,len);
                    //将内容显示在文本显示框(读文件是不需要申请权限的)
                    txt.setText(str2);
                    //关闭流
                    fis.close();


                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
            default:
                break;
        }
    }
}

效果图:
在这里插入图片描述


3、 动态权限(6.0以上)

注意:android6.0以上,需要动态申请权限。

方法一:手动打开外部存储权限。设置 --> 应用 --> 权限打开,即可

方法二:
在这里插入图片描述

在onCreate()方法中添加以下代码

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        
        ... ... 

        /**
         * 进入页面就开始请求权限
         */
        int permission=ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if(permission!=PackageManager.PERMISSION_GRANTED){
            //动态申请权限
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
        }
    }

效果图:
在这里插入图片描述在这里插入图片描述


4、 获取外部存储的目录

获取根目录
Environment.getExternalStorageDirectory()

操作外部存储的公有目录
Environment.getExternalStorageDirectory()+目录名称

操作外部存储的私有目录
在这里插入图片描述

都位于私有目录中间

应用程序在运行的过程中如果需要向手机上保存数据,一般是把数据保存在sdcard (外部存储的根目录) 中的。
大部分应用是直接在sdcard的根目录下创建一个文件夹,然后把数据保存在该文件夹中。
弊端: 这样当该应用被卸载后,这些数据还保留在sdcard中,留下了垃圾数据。

如果你想让你的应用被卸载后,与该应用相关的数据也清除掉,该怎么办呢???

通过 Context.getExernalFilesDir(String type)(type指定放在哪种文件类型下) 方法可以获取到 SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据

通过 Context.getExernalCacheDir() 方法可以获取到 SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据

好处: 如果使用上面的方法,当你的应用在被用户卸载后,sdcard/Android/data/你的应用的包名/ 这个目录下的所有文件都会被删除,不会留下垃圾信息。

而且上面二个目录分别对应 设置->应用->应用详情 里面的”清除数据“与”清除缓存“选项

如果要保存下载的内容,就不要放在以上目录下。

这两个文件夹操作权限问题:不需要任何权限,可以直接操作


三、内部存储InternalStorage

1、概念

在这里插入图片描述
在这里插入图片描述
app:放置app的apk文件
data:和应用的包名相关

包名下:
在这里插入图片描述

databases:数据库文件
files:普通文件
cache:缓存文件
shared_prefs:SharedPreferences文件


2、获取内存存储的目录

相关方法:
在这里插入图片描述

与外部存储获取目录的方法进行对比:在这里插入图片描述

作用相似:不管是放置在内部存储中间,还是外部存储中间,随着应用被卸载或者缓存被清除,内容也会随之消失

选择原则:当sdcard不存在或者被移除的情况下,采用内部存储中的两个方法,否则采用外部存储中的两个方法,获取与应用相关的目录, 进行数据的存储

相同点:
①都是使用 Context.方法名 获取目录
②从本质上说,以上目录都是私有目录,只是一个在内部存储中,一个在外部存储


3、代码演示

activity_internal.xml

<?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"
    tools:context=".InternalActivity">



    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="22dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:maxLines="13"
        android:minLines="13"
        android:hint="请输入待存储的内容..."
        android:gravity="left|top"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/read_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:text="读取"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/save_btn"
        app:layout_constraintTop_toTopOf="parent"
        android:onClick="operate" />

    <Button
        android:id="@+id/save_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:text="保存"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:onClick="operate" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="176dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

InternalActivity(写入内部存储文件)

不需要写入权限

写入步骤:

1、创建文件输出流(参数:传入文件目录) 不追加,直接用新的内容覆盖老的内容
FileOutputStream fos=new FileOutputStream(file);

2、获取输入框的内容,转化为String类型,然后以字节流的方式写入内容

fos.write(edt.getText().toString().getBytes());

3、关闭输出流对象
fos.close();

具体代码:

package com.example.storagestudy;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import org.w3c.dom.Text;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;


/**
 * function:
 * Created by TMJ on 2020-02-22.
 */
public class InternalActivity extends AppCompatActivity {

    private EditText edt;
    private TextView txt;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_internal);

        //初始化控件
        edt = (EditText)findViewById(R.id.editText);
        txt = (TextView)findViewById(R.id.textView);


    }

    /**
     * 在activity_external.xml布局文件中添加点击事件属性,来注册点击事件
     * @param view
     */
    public void operate(View view) {
    
		//新建一个文件
        File file=new File(getFilesDir(),"getFilesDir.txt");

        switch (view.getId()){

            case R.id.save_btn:
             
                try{
                    //若文件不存在,则创建一个新的文件
                    if(!file.exists()){
                        file.createNewFile();
                    }
                     /**
                     * 存储信息
                     */
                    //创建文件输出流(参数1:传入文件目录) 不追加,直接用新的内容覆盖老的内容
                    FileOutputStream fos=new FileOutputStream(file);
                    //获取输入框的内容,转化为String类型,然后以字节流的方式写入内容
                    fos.write(edt.getText().toString().getBytes());
                    //关闭流
                    fos.close();

                }
                catch (IOException e) {
                    e.printStackTrace();
                }
                
	 			break;

            case R.id.read_btn:

                break;
        }
    }
}

data --> data --> 该包名com.example.storage --> files --> 生成普通文件getFileDir.txt

在这里插入图片描述
在这里插入图片描述

getFileDir.txt文件内容:

🍰😣😜

InternalActivity(读取内部存储文件)

读取步骤:

1、创建文件输入流
FileInputStream fis = new FileInputStream(file);
2、创建字节数组
byte[] b = new byte[1024];
3、读取输入流内容(读取的内容存储在字节数组中),返回读取到的长度
int len= fis.read(b);
4、利用保存读取内容的字节数组,生成字符串
String str2=new String(b,0,len);
5、将内容显示在文本显示框(读文件是不需要申请权限的)
txt.setText(str2);
6、关闭流
fis.close();

具体代码:

public class InternalActivity extends AppCompatActivity {

    ... ...
    /**
     * 在activity_external.xml布局文件中添加点击事件属性,来注册点击事件
     */
    public void operate(View view) {

        //新建一个文件
        File file=new File(getFilesDir(),"getFilesDir.txt");

        switch (view.getId()){

            case R.id.save_btn:

                	... ...
                	
                    break;

            case R.id.read_btn:

                try {
                    //创建文件输入流
                    FileInputStream fis = new FileInputStream(file);
                    //创建字节数组
                    byte[] b = new byte[1024];
                    //读取输入流内容(读取的内容存储在字节数组中),返回读取到的长度
                    int len= fis.read(b);
                    //利用保存读取内容的字节数组,生成字符串
                    String str2=new String(b,0,len);
                    //将内容显示在文本显示框(读文件是不需要申请权限的)
                    txt.setText(str2);
                    //关闭流
                    fis.close();

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
        }
    }
}

效果图:
在这里插入图片描述


四、开发过程中的异常处理

1、FileNotFound异常

在这里插入图片描述

在访问外部存储之前一定要先判断外部存储是否已经是可使用状态

MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读/写
在这里插入图片描述

参考资料:Environment类:外部存储状态获取


2、DDMS中data、sdcard目录无法展开

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值