数据存储——四种存储方式——存储卡的文件操作——在存储卡上读写文本文件
==========================================================================================
添加权限:
<!-- 存储卡读写 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android10新增权限MANAGE_EXTERNAL_STORAGE --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
第一个页面布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" > <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" > <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="姓名:" android:textColor="@color/black" android:textSize="17sp" /> <EditText android:id="@+id/et_name" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="3dp" android:layout_marginTop="3dp" android:layout_toRightOf="@+id/tv_name" android:background="@drawable/editext_selector" android:gravity="left|center" android:hint="请输入姓名" android:inputType="text" android:maxLength="12" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" > <TextView android:id="@+id/tv_age" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="年龄:" android:textColor="@color/black" android:textSize="17sp" /> <EditText android:id="@+id/et_age" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="3dp" android:layout_marginTop="3dp" android:layout_toRightOf="@+id/tv_age" android:background="@drawable/editext_selector" android:gravity="left|center" android:hint="请输入年龄" android:inputType="number" android:maxLength="2" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" > <TextView android:id="@+id/tv_height" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="身高:" android:textColor="@color/black" android:textSize="17sp" /> <EditText android:id="@+id/et_height" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="3dp" android:layout_marginTop="3dp" android:layout_toRightOf="@+id/tv_height" android:background="@drawable/editext_selector" android:gravity="left|center" android:hint="请输入身高" android:inputType="number" android:maxLength="3" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" > <TextView android:id="@+id/tv_weight" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="体重:" android:textColor="@color/black" android:textSize="17sp" /> <EditText android:id="@+id/et_weight" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="3dp" android:layout_marginTop="3dp" android:layout_toRightOf="@+id/tv_weight" android:background="@drawable/editext_selector" android:gravity="left|center" android:hint="请输入体重" android:inputType="numberDecimal" android:maxLength="5" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" > <CheckBox android:id="@+id/ck_married" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:checked="false" android:text="已婚" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <Button android:id="@+id/btn_save" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="保存文本到存储卡" android:textColor="@color/black" android:textSize="17sp" /> <TextView android:id="@+id/tv_path" android:layout_width="wrap_content" android:layout_height="match_parent" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout>
第一个页面代码:
package com.example.myapplication; import android.content.Intent; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { private EditText et_name; private EditText et_age; private EditText et_height; private EditText et_weight; private boolean isMarried = false; private String[] typeArray = {"未婚", "已婚"}; private String mPath; // 私有目录路径 private TextView tv_path; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_name = findViewById(R.id.et_name); et_age = findViewById(R.id.et_age); et_height = findViewById(R.id.et_height); et_weight = findViewById(R.id.et_weight); tv_path = findViewById(R.id.tv_path); CheckBox ck_married = findViewById(R.id.ck_married); ck_married.setOnCheckedChangeListener(this); findViewById(R.id.btn_save).setOnClickListener(this); // 获取当前App的私有下载目录 mPath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/"; } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { isMarried = isChecked; } @Override public void onClick(View v) { if (v.getId() == R.id.btn_save) { String name = et_name.getText().toString(); String age = et_age.getText().toString(); String height = et_height.getText().toString(); String weight = et_weight.getText().toString(); if (TextUtils.isEmpty(name)) { ToastUtil.show(this, "请先填写姓名"); return; } else if (TextUtils.isEmpty(age)) { ToastUtil.show(this, "请先填写年龄"); return; } else if (TextUtils.isEmpty(height)) { ToastUtil.show(this, "请先填写身高"); return; } else if (TextUtils.isEmpty(weight)) { ToastUtil.show(this, "请先填写体重"); return; } String content = String.format(" 姓名:%s\n 年龄:%s\n 身高:%scm\n 体重:%skg\n 婚否:%s\n 注册时间:%s\n", name, age, height, weight, typeArray[isMarried?1:0], DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss")); String file_path = mPath + DateUtil.getNowDateTime("") + ".txt"; FileUtil.saveText(file_path, content); // 把字符串内容保存为文本文件 tv_path.setText("用户注册信息文件的保存路径为:\n" + file_path); ToastUtil.show(this, "数据已写入存储卡文件"); } startActivity(new Intent(this,MainActivity2.class)); } }
工具类:
package com.example.myapplication; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; public class FileUtil { // 把字符串保存到指定路径的文本文件 public static void saveText(String path, String txt) { // 根据指定的文件路径构建文件输出流对象 try (FileOutputStream fos = new FileOutputStream(path)) { fos.write(txt.getBytes()); // 把字符串写入文件输出流 } catch (Exception e) { e.printStackTrace(); } } // 从指定路径的文本文件中读取内容字符串 public static String openText(String path) { String readStr = ""; // 根据指定的文件路径构建文件输入流对象 try (FileInputStream fis = new FileInputStream(path)) { byte[] b = new byte[fis.available()]; fis.read(b); // 从文件输入流读取字节数组 readStr = new String(b); // 把字节数组转换为字符串 } catch (Exception e) { e.printStackTrace(); } return readStr; // 返回文本文件中的文本字符串 } // 把位图数据保存到指定路径的图片文件 public static void saveImage(String path, Bitmap bitmap) { // 根据指定的文件路径构建文件输出流对象 try (FileOutputStream fos = new FileOutputStream(path)) { // 把位图数据压缩到文件输出流中 bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos); } catch (Exception e) { e.printStackTrace(); } } // 从指定路径的图片文件中读取位图数据 public static Bitmap openImage(String path) { Bitmap bitmap = null; // 声明一个位图对象 // 根据指定的文件路径构建文件输入流对象 try (FileInputStream fis = new FileInputStream(path)) { bitmap = BitmapFactory.decodeStream(fis); // 从文件输入流中解码位图数据 } catch (Exception e) { e.printStackTrace(); } return bitmap; // 返回图片文件中的位图数据 } public static List<File> getFileList(String path, String[] extendArray) { List<File> displayedContent = new ArrayList<File>(); File[] files = null; File directory = new File(path); if (extendArray != null && extendArray.length > 0) { FilenameFilter fileFilter = getTypeFilter(extendArray); files = directory.listFiles(fileFilter); } else { files = directory.listFiles(); } if (files != null) { for (File f : files) { if (!f.isDirectory() && !f.isHidden()) { displayedContent.add(f); } } } // 按照最后修改时间排序 Collections.sort(displayedContent, new Comparator<File>() { @Override public int compare(File o1, File o2) { return (o1.lastModified() > o2.lastModified()) ? -1 : 1; } }); return displayedContent; } public static FilenameFilter getTypeFilter(String[] extendArray) { final ArrayList<String> fileExtensions = new ArrayList<String>(); for (int i = 0; i < extendArray.length; i++) { fileExtensions.add(extendArray[i]); } FilenameFilter fileNameFilter = new FilenameFilter() { @Override public boolean accept(File directory, String fileName) { boolean matched = false; File f = new File(String.format("%s/%s", directory.getAbsolutePath(), fileName)); matched = f.isDirectory(); if (!matched) { for (String s : fileExtensions) { s = String.format(".{0,}\\%s$", s); s = s.toUpperCase(Locale.getDefault()); fileName = fileName.toUpperCase(Locale.getDefault()); matched = fileName.matches(s); if (matched) { break; } } } return matched; } }; return fileNameFilter; } }
package com.example.myapplication; import android.content.Context; import android.widget.Toast; public class ToastUtil { public static void show(Context ctx, String desc) { Toast.makeText(ctx, desc, Toast.LENGTH_SHORT).show(); } }
第二个页面布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" > <Button android:id="@+id/btn_delete" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="删除所有文本文件" android:textColor="@color/black" android:textSize="17sp" /> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout>
第二个页面代码:
package com.example.myapplication; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import java.io.File; import java.util.ArrayList; import java.util.List; public class MainActivity2 extends AppCompatActivity implements View.OnClickListener { private final static String TAG = "FileReadActivity"; private TextView tv_content; private String mPath; // 私有目录路径 private List<File> mFilelist = new ArrayList<File>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); tv_content = findViewById(R.id.tv_content); findViewById(R.id.btn_delete).setOnClickListener(this); // 获取当前App的私有下载目录 mPath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/"; showFileContent(); // 显示最新的文本文件内容 } // 显示最新的文本文件内容 private void showFileContent() { // 获得指定目录下面的所有文本文件 mFilelist = FileUtil.getFileList(mPath, new String[]{".txt"}); if (mFilelist.size() > 0) { // 打开并显示选中的文本文件内容 String file_path = mFilelist.get(0).getAbsolutePath(); String content = FileUtil.openText(file_path); String desc = String.format("找到最新的文本文件,路径为%s,内容如下:\n%s", file_path, content); tv_content.setText(desc); } else { tv_content.setText("私有目录下未找到任何文本文件"); } } @Override public void onClick(View v) { if (v.getId() == R.id.btn_delete) { for (int i = 0; i < mFilelist.size(); i++) { String file_path = mFilelist.get(i).getAbsolutePath(); File f = new File(file_path); if (!f.delete()) { Log.d(TAG, "file_path=" + file_path + ", delete failed"); } } ToastUtil.show(this, "已删除私有目录下的所有文本文件"); } } }
======================================================================================