前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 存储媒体已经挂载,并且挂载点可读/写