当前位置:   article > 正文

Android Studio开发之存储卡的文件操作讲解及实战(附源码 在存储卡上读写文本文件和图片文件)_android studio读取sd卡

android studio读取sd卡

一、私有存储空间和公共存储空间

为了更规范的管理手机存储空间,Android从7.0开始将存储卡划分为私有存储和公共存储两大部分,也就是分区存储方式,系统给每个App都分配了默认的私有存储空间,App在私有空间上读写文件无须任何授权,但是若想在公共空间读写文件,则要在AndroidManifest.xml里面添加权限配置,并且即使App声明了完整的存储卡操作权限,系统仍然默认禁止该App访问公共空间,打开系统的系统设置界面,进入到具体应用的管理页面,然后打开该应用的存储访问权限。

既然存储卡分为公共空间和私有空间两部分,它们的空间路径获取也就有所不同。如下图所示

 FilePathActivity类

  1. package com.example.chapter06;
  2. import android.os.Build;
  3. import android.os.Bundle;
  4. import android.os.Environment;
  5. import android.widget.TextView;
  6. import androidx.appcompat.app.AppCompatActivity;
  7. public class FilePathActivity extends AppCompatActivity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_file_path);
  12. TextView tv_path = findViewById(R.id.tv_path);
  13. // Android7.0之后默认禁止访问公共存储目录
  14. // 获取系统的公共存储路径
  15. String publicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
  16. // 获取当前App的私有存储路径
  17. String privatePath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
  18. boolean isLegacy = true;
  19. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
  20. // Android10的存储空间默认采取分区方式,此处判断是传统方式还是分区方式
  21. isLegacy = Environment.isExternalStorageLegacy();
  22. }
  23. String desc = "系统的公共存储路径位于" + publicPath +
  24. "\n\n当前App的私有存储路径位于" + privatePath +
  25. "\n\nAndroid7.0之后默认禁止访问公共存储目录" +
  26. "\n\n当前App的存储空间采取" + (isLegacy?"传统方式":"分区方式");
  27. tv_path.setText(desc);
  28. }
  29. }

activity_file_pathXML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. android:padding="5dp" >
  6. <TextView
  7. android:id="@+id/tv_path"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:textColor="@color/black"
  11. android:textSize="17sp" />
  12. </LinearLayout>

二、在存储卡上读写文本文件

文本文件的读写借助于文件IO流FileOutputStream和FileInputStream 效果如下

 

一键删除后效果如下 

 

 FileReadActivity类

  1. package com.example.chapter06;
  2. import android.annotation.SuppressLint;
  3. import android.os.Bundle;
  4. import android.os.Environment;
  5. import android.util.Log;
  6. import android.view.View;
  7. import android.widget.TextView;
  8. import androidx.appcompat.app.AppCompatActivity;
  9. import com.example.chapter06.util.FileUtil;
  10. import com.example.chapter06.util.ToastUtil;
  11. import java.io.File;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14. @SuppressLint("SetTextI18n")
  15. public class FileReadActivity extends AppCompatActivity implements View.OnClickListener {
  16. private final static String TAG = "FileReadActivity";
  17. private TextView tv_content;
  18. private String mPath; // 私有目录路径
  19. private List<File> mFilelist = new ArrayList<File>();
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(R.layout.activity_file_read);
  24. tv_content = findViewById(R.id.tv_content);
  25. findViewById(R.id.btn_delete).setOnClickListener(this);
  26. // 获取当前App的私有下载目录
  27. mPath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
  28. showFileContent(); // 显示最新的文本文件内容
  29. }
  30. // 显示最新的文本文件内容
  31. private void showFileContent() {
  32. // 获得指定目录下面的所有文本文件
  33. mFilelist = FileUtil.getFileList(mPath, new String[]{".txt"});
  34. if (mFilelist.size() > 0) {
  35. // 打开并显示选中的文本文件内容
  36. String file_path = mFilelist.get(0).getAbsolutePath();
  37. String content = FileUtil.openText(file_path);
  38. String desc = String.format("找到最新的文本文件,路径为%s,内容如下:\n%s",
  39. file_path, content);
  40. tv_content.setText(desc);
  41. } else {
  42. tv_content.setText("私有目录下未找到任何文本文件");
  43. }
  44. }
  45. @Override
  46. public void onClick(View v) {
  47. if (v.getId() == R.id.btn_delete) {
  48. for (int i = 0; i < mFilelist.size(); i++) {
  49. String file_path = mFilelist.get(i).getAbsolutePath();
  50. File f = new File(file_path);
  51. if (!f.delete()) {
  52. Log.d(TAG, "file_path=" + file_path + ", delete failed");
  53. }
  54. }
  55. ToastUtil.show(this, "已删除私有目录下的所有文本文件");
  56. }
  57. }
  58. }

FileWriteActivity类

  1. package com.example.chapter06;
  2. import android.annotation.SuppressLint;
  3. import android.os.Bundle;
  4. import android.os.Environment;
  5. import android.text.TextUtils;
  6. import android.view.View;
  7. import android.widget.CheckBox;
  8. import android.widget.CompoundButton;
  9. import android.widget.EditText;
  10. import android.widget.TextView;
  11. import androidx.appcompat.app.AppCompatActivity;
  12. import com.example.chapter06.util.DateUtil;
  13. import com.example.chapter06.util.FileUtil;
  14. import com.example.chapter06.util.ToastUtil;
  15. @SuppressLint("SetTextI18n")
  16. public class FileWriteActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
  17. private EditText et_name;
  18. private EditText et_age;
  19. private EditText et_height;
  20. private EditText et_weight;
  21. private boolean bMarried = false;
  22. private String[] typeArray = {"未婚", "已婚"};
  23. private String mPath; // 私有目录路径
  24. private TextView tv_path;
  25. @Override
  26. protected void onCreate(Bundle savedInstanceState) {
  27. super.onCreate(savedInstanceState);
  28. setContentView(R.layout.activity_file_write);
  29. et_name = findViewById(R.id.et_name);
  30. et_age = findViewById(R.id.et_age);
  31. et_height = findViewById(R.id.et_height);
  32. et_weight = findViewById(R.id.et_weight);
  33. tv_path = findViewById(R.id.tv_path);
  34. CheckBox ck_married = findViewById(R.id.ck_married);
  35. ck_married.setOnCheckedChangeListener(this);
  36. findViewById(R.id.btn_save).setOnClickListener(this);
  37. // 获取当前App的私有下载目录
  38. mPath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
  39. }
  40. @Override
  41. public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
  42. bMarried = isChecked;
  43. }
  44. @Override
  45. public void onClick(View v) {
  46. if (v.getId() == R.id.btn_save) {
  47. String name = et_name.getText().toString();
  48. String age = et_age.getText().toString();
  49. String height = et_height.getText().toString();
  50. String weight = et_weight.getText().toString();
  51. if (TextUtils.isEmpty(name)) {
  52. ToastUtil.show(this, "请先填写姓名");
  53. return;
  54. } else if (TextUtils.isEmpty(age)) {
  55. ToastUtil.show(this, "请先填写年龄");
  56. return;
  57. } else if (TextUtils.isEmpty(height)) {
  58. ToastUtil.show(this, "请先填写身高");
  59. return;
  60. } else if (TextUtils.isEmpty(weight)) {
  61. ToastUtil.show(this, "请先填写体重");
  62. return;
  63. }
  64. String content = String.format(" 姓名:%s\n 年龄:%s\n 身高:%scm\n 体重:%skg\n 婚否:%s\n 注册时间:%s\n",
  65. name, age, height, weight, typeArray[bMarried?1:0], DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss"));
  66. String file_path = mPath + DateUtil.getNowDateTime("") + ".txt";
  67. FileUtil.saveText(file_path, content); // 把字符串内容保存为文本文件
  68. tv_path.setText("用户注册信息文件的保存路径为:\n" + file_path);
  69. ToastUtil.show(this, "数据已写入存储卡文件");
  70. }
  71. }
  72. }

activity_file_readXML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. android:padding="5dp" >
  6. <Button
  7. android:id="@+id/btn_delete"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:text="删除所有文本文件"
  11. android:textColor="@color/black"
  12. android:textSize="17sp" />
  13. <TextView
  14. android:id="@+id/tv_content"
  15. android:layout_width="match_parent"
  16. android:layout_height="wrap_content"
  17. android:textColor="@color/black"
  18. android:textSize="17sp" />
  19. </LinearLayout>

activity_file_writeXML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. android:padding="5dp" >
  6. <RelativeLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="40dp" >
  9. <TextView
  10. android:id="@+id/tv_name"
  11. android:layout_width="wrap_content"
  12. android:layout_height="match_parent"
  13. android:gravity="center"
  14. android:text="姓名:"
  15. android:textColor="@color/black"
  16. android:textSize="17sp" />
  17. <EditText
  18. android:id="@+id/et_name"
  19. android:layout_width="match_parent"
  20. android:layout_height="match_parent"
  21. android:layout_marginBottom="3dp"
  22. android:layout_marginTop="3dp"
  23. android:layout_toRightOf="@+id/tv_name"
  24. android:background="@drawable/editext_selector"
  25. android:gravity="left|center"
  26. android:hint="请输入姓名"
  27. android:inputType="text"
  28. android:maxLength="12"
  29. android:textColor="@color/black"
  30. android:textSize="17sp" />
  31. </RelativeLayout>
  32. <RelativeLayout
  33. android:layout_width="match_parent"
  34. android:layout_height="40dp" >
  35. <TextView
  36. android:id="@+id/tv_age"
  37. android:layout_width="wrap_content"
  38. android:layout_height="match_parent"
  39. android:gravity="center"
  40. android:text="年龄:"
  41. android:textColor="@color/black"
  42. android:textSize="17sp" />
  43. <EditText
  44. android:id="@+id/et_age"
  45. android:layout_width="match_parent"
  46. android:layout_height="match_parent"
  47. android:layout_marginBottom="3dp"
  48. android:layout_marginTop="3dp"
  49. android:layout_toRightOf="@+id/tv_age"
  50. android:background="@drawable/editext_selector"
  51. android:gravity="left|center"
  52. android:hint="请输入年龄"
  53. android:inputType="number"
  54. android:maxLength="2"
  55. android:textColor="@color/black"
  56. android:textSize="17sp" />
  57. </RelativeLayout>
  58. <RelativeLayout
  59. android:layout_width="match_parent"
  60. android:layout_height="40dp" >
  61. <TextView
  62. android:id="@+id/tv_height"
  63. android:layout_width="wrap_content"
  64. android:layout_height="match_parent"
  65. android:gravity="center"
  66. android:text="身高:"
  67. android:textColor="@color/black"
  68. android:textSize="17sp" />
  69. <EditText
  70. android:id="@+id/et_height"
  71. android:layout_width="match_parent"
  72. android:layout_height="match_parent"
  73. android:layout_marginBottom="3dp"
  74. android:layout_marginTop="3dp"
  75. android:layout_toRightOf="@+id/tv_height"
  76. android:background="@drawable/editext_selector"
  77. android:gravity="left|center"
  78. android:hint="请输入身高"
  79. android:inputType="number"
  80. android:maxLength="3"
  81. android:textColor="@color/black"
  82. android:textSize="17sp" />
  83. </RelativeLayout>
  84. <RelativeLayout
  85. android:layout_width="match_parent"
  86. android:layout_height="40dp" >
  87. <TextView
  88. android:id="@+id/tv_weight"
  89. android:layout_width="wrap_content"
  90. android:layout_height="match_parent"
  91. android:gravity="center"
  92. android:text="体重:"
  93. android:textColor="@color/black"
  94. android:textSize="17sp" />
  95. <EditText
  96. android:id="@+id/et_weight"
  97. android:layout_width="match_parent"
  98. android:layout_height="match_parent"
  99. android:layout_marginBottom="3dp"
  100. android:layout_marginTop="3dp"
  101. android:layout_toRightOf="@+id/tv_weight"
  102. android:background="@drawable/editext_selector"
  103. android:gravity="left|center"
  104. android:hint="请输入体重"
  105. android:inputType="numberDecimal"
  106. android:maxLength="5"
  107. android:textColor="@color/black"
  108. android:textSize="17sp" />
  109. </RelativeLayout>
  110. <RelativeLayout
  111. android:layout_width="match_parent"
  112. android:layout_height="40dp" >
  113. <CheckBox
  114. android:id="@+id/ck_married"
  115. android:layout_width="wrap_content"
  116. android:layout_height="match_parent"
  117. android:gravity="center"
  118. android:checked="false"
  119. android:text="已婚"
  120. android:textColor="@color/black"
  121. android:textSize="17sp" />
  122. </RelativeLayout>
  123. <Button
  124. android:id="@+id/btn_save"
  125. android:layout_width="match_parent"
  126. android:layout_height="wrap_content"
  127. android:text="保存文本到存储卡"
  128. android:textColor="@color/black"
  129. android:textSize="17sp" />
  130. <TextView
  131. android:id="@+id/tv_path"
  132. android:layout_width="wrap_content"
  133. android:layout_height="match_parent"
  134. android:textColor="@color/black"
  135. android:textSize="17sp" />
  136. </LinearLayout>

三、在存储卡上读写图片文件

文本文件读写可以转换为对字符串的读写,而图片文件保存的是图像数据,需要专门的位图工具Bitmap处理,位图对象依据来源不同又分成3种获取方式,分别对应位图工厂BitmapFactory的下列三种方法

1:decodeResource  从指定路径的文件种获取位图数据

2:decodeFile  从指定路径的文件中获取位图数据

3:decodeStream  从指定的输入流中获取位图数据

 ImageWriteActivity类

  1. package com.example.chapter06;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.os.Bundle;
  6. import android.os.Environment;
  7. import android.view.View;
  8. import android.widget.ImageView;
  9. import android.widget.TextView;
  10. import com.example.chapter06.util.DateUtil;
  11. import com.example.chapter06.util.FileUtil;
  12. import com.example.chapter06.util.ToastUtil;
  13. public class ImageWriteActivity extends AppCompatActivity implements View.OnClickListener {
  14. private ImageView iv_content;
  15. private TextView tv_path;
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_image_write);
  20. iv_content = findViewById(R.id.iv_content);
  21. iv_content.setImageResource(R.drawable.vivo); // 设置图像视图的图片资源
  22. tv_path = findViewById(R.id.tv_path);
  23. findViewById(R.id.btn_save).setOnClickListener(this);
  24. }
  25. @Override
  26. public void onClick(View v) {
  27. if (v.getId() == R.id.btn_save) {
  28. // 获取当前App的私有下载目录
  29. String path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
  30. // 从指定的资源文件中获取位图对象
  31. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.huawei);
  32. String file_path = path + DateUtil.getNowDateTime("") + ".jpeg";
  33. FileUtil.saveImage(file_path, bitmap); // 把位图对象保存为图片文件
  34. tv_path.setText("图片文件的保存路径为:\n" + file_path);
  35. ToastUtil.show(this, "图片已写入存储卡文件");
  36. }
  37. }
  38. }

ImageReadActivity类

  1. package com.example.chapter06;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.net.Uri;
  6. import android.os.Bundle;
  7. import android.os.Environment;
  8. import android.util.Log;
  9. import android.view.View;
  10. import android.widget.ImageView;
  11. import android.widget.TextView;
  12. import com.example.chapter06.util.FileUtil;
  13. import com.example.chapter06.util.ToastUtil;
  14. import java.io.File;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. public class ImageReadActivity extends AppCompatActivity implements View.OnClickListener {
  18. private final static String TAG = "ImageReadActivity";
  19. private TextView tv_content;
  20. private ImageView iv_content;
  21. private String mPath; // 私有目录路径
  22. private List<File> mFilelist = new ArrayList<File>();
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.activity_image_read);
  27. tv_content = findViewById(R.id.tv_content);
  28. iv_content = findViewById(R.id.iv_content);
  29. findViewById(R.id.btn_delete).setOnClickListener(this);
  30. // 获取当前App的私有下载目录
  31. mPath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
  32. showFileContent(); // 显示最新的图片文件内容
  33. }
  34. // 显示最新的图片文件内容
  35. private void showFileContent() {
  36. // 获得指定目录下面的所有图片文件
  37. mFilelist = FileUtil.getFileList(mPath, new String[]{".jpeg"});
  38. if (mFilelist.size() > 0) {
  39. // 打开并显示选中的图片文件内容
  40. String file_path = mFilelist.get(0).getAbsolutePath();
  41. tv_content.setText("找到最新的图片文件,路径为"+file_path);
  42. // 显示存储卡图片文件的第一种方式:直接调用setImageURI方法
  43. //iv_content.setImageURI(Uri.parse(file_path)); // 设置图像视图的路径对象
  44. // 第二种方式:先调用BitmapFactory.decodeFile获得位图,再调用setImageBitmap方法
  45. //Bitmap bitmap = BitmapFactory.decodeFile(file_path);
  46. //iv_content.setImageBitmap(bitmap); // 设置图像视图的位图对象
  47. // 第三种方式:先调用FileUtil.openImage获得位图,再调用setImageBitmap方法
  48. Bitmap bitmap = FileUtil.openImage(file_path);
  49. iv_content.setImageBitmap(bitmap); // 设置图像视图的位图对象
  50. } else {
  51. tv_content.setText("私有目录下未找到任何图片文件");
  52. }
  53. }
  54. @Override
  55. public void onClick(View v) {
  56. if (v.getId() == R.id.btn_delete) {
  57. for (int i = 0; i < mFilelist.size(); i++) {
  58. // 获取该文件的绝对路径字符串
  59. String file_path = mFilelist.get(i).getAbsolutePath();
  60. File f = new File(file_path);
  61. if (!f.delete()) { // 删除文件,并判断是否成功删除
  62. Log.d(TAG, "file_path=" + file_path + ", delete failed");
  63. }
  64. }
  65. ToastUtil.show(this, "已删除私有目录下的所有图片文件");
  66. }
  67. }
  68. }

activity_image_readXML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. android:padding="5dp" >
  6. <Button
  7. android:id="@+id/btn_delete"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:text="删除所有图片文件"
  11. android:textColor="@color/black"
  12. android:textSize="17sp" />
  13. <TextView
  14. android:id="@+id/tv_content"
  15. android:layout_width="match_parent"
  16. android:layout_height="wrap_content"
  17. android:textColor="@color/black"
  18. android:textSize="17sp" />
  19. <ImageView
  20. android:id="@+id/iv_content"
  21. android:layout_width="match_parent"
  22. android:layout_height="250dp"
  23. android:scaleType="fitCenter" />
  24. </LinearLayout>

activity_image_writeXML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. android:padding="5dp" >
  6. <ImageView
  7. android:id="@+id/iv_content"
  8. android:layout_width="match_parent"
  9. android:layout_height="250dp"
  10. android:scaleType="fitCenter" />
  11. <Button
  12. android:id="@+id/btn_save"
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content"
  15. android:text="把资源图片保存到存储卡"
  16. android:textColor="@color/black"
  17. android:textSize="17sp" />
  18. <TextView
  19. android:id="@+id/tv_path"
  20. android:layout_width="wrap_content"
  21. android:layout_height="match_parent"
  22. android:textColor="@color/black"
  23. android:textSize="17sp" />
  24. </LinearLayout>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/319365
推荐阅读
相关标签
  

闽ICP备14008679号