Android开发实现内部和外部存储文件
效果图:
activity_main.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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文件名字:"
android:textSize="35dp"></TextView>
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="35dp"></EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文件内容:"
android:textSize="35dp"></TextView>
<EditText
android:id="@+id/et_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="35dp"></EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:layout_weight="1"
android:text="存入INTERNAL文件"
android:onClick="Save_in"></Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:layout_weight="1"
android:text="存入EXTERNAL文件"
android:onClick="Save_ex"></Button>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Internal文件内容:"
android:textSize="30dp">
</TextView>
<TextView
android:id="@+id/incontent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp">
</TextView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="External文件内容:"
android:textSize="30dp">
</TextView>
<TextView
android:id="@+id/excontent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp">
</TextView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<Button
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="从INTERNAL取文件"
android:onClick="Out_in"></Button>
<Button
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="从EXTERNAL取文件"
android:onClick="Out_ex"></Button>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java代码:
package com.henu.saveinfile;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
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 android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.file.FileVisitOption;
public class MainActivity extends AppCompatActivity {
private EditText et_name;
private EditText et_content;
private TextView tv_in_content;
private TextView tv_ex_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = (EditText) findViewById(R.id.et_name);
et_content = (EditText) findViewById(R.id.et_content);
tv_in_content = (TextView) findViewById(R.id.incontent);
tv_ex_content = (TextView) findViewById(R.id.excontent);
//弹出请求获取存储权限的对话框
int REQUEST_EXTERNAL_STORAGE = 1;
String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
int permission = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
MainActivity.this,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
//存入内部存储区
public void Save_in(View v) {
FileOutputStream fos;
try {
fos = openFileOutput(et_name.getText().toString().trim(), Context.MODE_PRIVATE);
fos.write(et_content.getText().toString().trim().getBytes());
fos.close();
Toast.makeText(this, "存入内部成功", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//从内部存储区取出文件并显示
public void Out_in(View v) {
FileInputStream fis;
try {
fis = openFileInput(et_name.getText().toString().trim());
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
tv_in_content.setText(getFilesDir() + "/" + et_name.getText().toString().trim() + ".txt" + ":" + new String(buffer));
fis.close();
Toast.makeText(this, "从内部读取成功", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//判断外部存储区是否可用
public boolean isExternalStorageWritable() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
return true;
}
return false;
}
//把文件存入外部存储区
public void Save_ex(View v) {
if (isExternalStorageWritable()) {
File file = new File(Environment.getExternalStorageDirectory(), et_name.getText().toString().trim() + ".txt");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(et_content.getText().toString().trim().getBytes());
Toast.makeText(this, "创建成功", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
Toast.makeText(this, "请允许\"SavelInFile\"访问您设备上的照片、\n" +
"媒体内容和文件\n", Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "外部存储区不可用", Toast.LENGTH_SHORT).show();
}
}
//取出外部文件并显示出来
public void Out_ex(View v) {
File file = new File(Environment.getExternalStorageDirectory(), et_name.getText().toString().trim() + ".txt");
FileInputStream fis;
try {
fis = new FileInputStream(file);
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
tv_ex_content.setText(Environment.getExternalStorageDirectory().getPath() + "/" + et_name.getText().toString().trim() + ".txt" + ":" + new String(buffer));
Toast.makeText(this, "从外部读取成功", Toast.LENGTH_SHORT).show();
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
AndroidManifest.xml代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.henu.saveinfile">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>//获取外部存储区写的权限(有了写的权限就能有了读的权限)
<application
android:requestLegacyExternalStorage="true"//停用分区存储
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/Theme.SaveInFile">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
遇到的问题:
在外部存储文件时老是报错:FileNotFoundException,找不到文件。一般这样的问题有两个原因,一个是路径错误,一个是没有权限。我这是在创建文件时报错,所以原因是后者。但是我已经在AndroidManifest.xml文件中加入android:name=“android.permission.WRITE_EXTERNAL_STORAGE”/>获取到权限了,为什么还是报错。原来是安卓6版本以上,需要获取运行时权限。我又在加上对话框,在初次进入时弹出询问用户获取权限。
但是还是报错,FileNotFoundException。查了下原因,原来是Android 10之前,Android的文件存储现象就像个垃圾桶,但凡app取得了存储空间的读写权限WRITE_EXTERNAL_STORAGE,就可以肆意创建文件,难以管理。用户体验也特别差,打开文件管理器,会发现,想找个具体的文件根本无从下手。为了更好地管理自己的文件并减少混乱,加强隐私保护,Android Q开始引入了分区存储机制。外部存储空间被重新设计,按应用私有和公用共享划分。应用只能访问到自己私有空间,或者通过MediaStore API 和Storage Access Framework去访问共享的资源目录。
关闭了分区存储:android:requestLegacyExternalStorage="true"就能和原来一样在外部存储区肆意创建文件了 哈哈