Android文件存储

文件存储

这是之前用java写的一个文件工具类,区分了内部存储、外部存储,公共目录三个路径,有详细的注释,希望能帮助到大家。

import android.content.ContentResolver;
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;

import com.qdgbr.commodlue.api.BaseConstant;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.util.Objects;

/**
 * @author ThinkAgains
 * @date 2019/10/24
 * Description: 文件管理类
 * APP内部文件(不需要申请权限): (当用户卸载app时,文件会删除)
 * 1.cache 不可见
 * 2.getExternalFilesDir 包名下
 * APP外部文件(需要申请权限): (当用户卸载app时,文件会保留,安卓11已废弃两个方法)
 * 1.getExternalStorageDirectory 外置SD卡可以指定访问的文件夹名
 * 2.getStoragePath 外置SD卡路径
 * APP外部公共目录文件(需要申请权限)
 * 1.getExternalStoragePublicDirectory 外置SD卡公共目录(例如:Environment.DIRECTORY_PICTURES,路径固定)
 * <p>
 * 安卓11上外部存储不允许访问,只能访问公共目录,所以没有提供存储外部文件相关的处理,只提供了获取路径方法
 * 注意:外部存储需要判断是否有SD卡权限,Util方法中已经提供
 * if (Util.isExternalStorageWritable()) {
 * } else {
 * return null;
 * }
 */
public class FileUtils {
	
	 /**
     * 这个是fileProvider相关
     */
    private final static String FILE_PUBLIC = BaseConstant.APP_PACKAGE;
    public static final String FILE_PROVIDER = FILE_PUBLIC + ".selfFileProvider";

    /**
     * 图片缓存的文件名
     */
    public final static String FILE_MOVIES = "Movies";
    public final static String FILE_FILE = "File";
    public final static String FILE_PICTURES = "Pictures";
    public final static String FILE_MUSIC = "Music";

    public enum StorageInEnum {
        //APP内部cache目录
        APP_IN_CACHE,
        //APP内部包名目录
        APP_IN_PACKAGE
    }

    public enum FileInEnum {
        //文件
        FILE,
        //图片
        PICTURES,
        //录音
        MUSIC,
        //视频
        MOVIES
    }

    /**
     * 获取APP内部存储文件
     *
     * @param fileEnum 存储类型
     */
    public static File getAppStorageInFile(StorageInEnum storageEnum, FileInEnum fileEnum) {
        if (storageEnum == StorageInEnum.APP_IN_PACKAGE) {
            return FileInUtils.getPrivatePackAgeDir(fileEnum);
        } else if (storageEnum == StorageInEnum.APP_IN_CACHE) {
            return FileInUtils.getPrivateCacheDir(fileEnum);
        } else {
            return null;
        }
    }

    /**
     * 获取外部公共目录
     *
     * @param fileEnum 存储类型
     * @return Uri
     */
    public static Uri getPublicOutUri(FileInEnum fileEnum) {
        if (Util.isExternalStorageWritable()) {
            return getPublicOutUri(fileEnum, "");
        } else {
            return null;
        }
    }

    /**
     * 获取外部公共目录
     *
     * @param fileEnum 存储类型
     * @param fileName 文件名,不传默认为时间戳
     * @return Uri
     */
    public static Uri getPublicOutUri(FileInEnum fileEnum, String fileName) {
        if (Util.isExternalStorageWritable()) {
            return FilePublicOutUtils.getPublicDir(fileEnum, fileName);
        } else {
            return null;
        }
    }

    /**
     * 工具方法
     */
    public static class Util {

        private static final int BYTE = 1024;
        //在你申请储存权限并确认储存可用后,你可以储存下列档案:
        //公共文件:应该免费提供给其他应用程序和用户的文件。当用户卸载应用程序时,这些文件应该对用户可用。例如,应用程序捕获的照片应该保存为公共文件。
        //尽管这些文件在技术上可以由用户和其他应用程序,因为它们在外部存储上,他们不向用户提供价值以外的应用程序。使用这个目录文件,你不想与其他应用程序共享。
        //警告:如果用户删除或断开外部存储设备(如SD卡),存储在外部存储上的文件可能不可用。如果你的应用程序的功能依赖于这些文件,你应该把你的文件写到内部存储。

        //检查外部存储是否可用来读写
        private static boolean isExternalStorageWritable() {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                return true;
            }
            return false;
        }

        //检查外部存储是否至少可读
        private static boolean isExternalStorageReadable() {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state) ||
                    Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
                return true;
            }
            return false;
        }

        /**
         * 获取应用数据存储的大小
         */
        public static String getFilSizeText() {
            //cache目录
            //long folderSize = getFolderSize(FileInUtils.getRealCacheDir());
            //包名目录
            long folderSize = getFolderSize(FileInUtils.getRealPackAgeDir("").getParentFile());
            return getFormatSize(folderSize);
        }

        private static long getFolderSize(File file) {
            long size = 0;
            try {
                File[] fileList = file.listFiles();
                if (null != fileList) {
                    for (int i = 0; i < fileList.length; i++) {
                        if (fileList[i].isDirectory()) {
                            size = size + getFolderSize(fileList[i]);
                        } else {
                            size = size + fileList[i].length();
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return size;
        }

        /**
         * 清除缓存(删除应用中所有的文件)
         */
        public static void clearCache() {
            // 你应该总是删除你的应用程序不再需要的文件。删除文件最直接的方法是调用delete()对文件对象:
            //如果文件保存在内部存储器中,也可以通过调用deleteFile()来请求上下文查找和删除文件:
            deleteDirWithFile(FileInUtils.getRealPackAgeDir("").getParentFile());
        }

        private static void deleteDirWithFile(File dir) {
            if (dir == null || !fileIsExists(dir) || !dir.isDirectory()) {
                return;
            }
            for (File file : Objects.requireNonNull(dir.listFiles())) {
                if (file.isFile()) {
                    file.delete();
                } else if (file.isDirectory()) {
                    deleteDirWithFile(file);
                }
            }
            dir.delete();
        }

        /**
         * 格式化单位
         */
        private static String getFormatSize(long size) {
            DecimalFormat df = new DecimalFormat("#.00");
            double kiloByte = size / BYTE;
            if (kiloByte < 1) {
                return size + "B";
            }
            double megaByte = kiloByte / BYTE;
            if (megaByte < 1) {
                return df.format(kiloByte) + "KB";
            }
            double gigaByte = megaByte / BYTE;
            if (gigaByte < 1) {
                return df.format(megaByte) + "MB";
            }
            double teraBytes = gigaByte / BYTE;
            if (teraBytes < 1) {
                return df.format(gigaByte) + "GB";
            }
            return df.format(teraBytes) + "TB";
        }

        /**
         * 文件是否存在
         *
         * @param file
         * @return true false
         */
        public static boolean fileIsExists(File file) {
            return file.exists();
            /* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
             //检查公共目录是否存在
             AssetFileDescriptor afd = null;
                ContentResolver cr = ContextUtils.getApp().getContentResolver();
                try {
                    Uri uri = Uri.parse(file.getAbsolutePath());
                    afd = cr.openAssetFileDescriptor(uri, "r");
                    if (afd == null) {
                        return false;
                    }
                } catch (FileNotFoundException e) {
                    return false;
                } finally {
                    try {
                        if (null != afd) {
                            afd.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return true;
            } else {
                return file.exists();
            }*/
        }
    }

    /**
     * 将一个文件保存到APP内部相关目录
     * 私有文件
     */
    private static class FileInUtils {

        //APP内部存储缓存文件(不可见的那部分存储)
        public static File getRealCacheDir() {
            return ContextUtils.Companion.getApp().getCacheDir();
        }

        //APP内部存储包名files目录文件
        public static File getRealPackAgeDir(String fileDirType) {
            return ContextUtils.Companion.getApp().getExternalFilesDir(fileDirType);
        }

        //效果同 getRealPackAgeDir(fileDirType)
        public static File getFilesDir() {
            return ContextUtils.Companion.getApp().getFilesDir();
        }

        //获取APP内部存储文件系统上的目录(文件名为:cache,该文件不可见)
        public static File getPrivateCacheDir(FileInEnum fileEnum) {
            //getCacheDir()返回一个File对象,该对象表示文件系统上与应用程序唯一关联的缓存目录。该目录用于临时文件,应该定期清理。
            //如果磁盘空间不足,系统可能会删除那里的文件,所以请确保在读取缓存文件之前检查它们的存在性
            //Uri.parse(url).getLastPathSegment():从URL对象中提取文件名,并在应用程序的内部缓存目录中创建一个同名文件
            //File.createTempFile(FileUtils.FILE_NAME, null, context.getCacheDir());创建临时文件
            String fileDirName;
            if (fileEnum == FileInEnum.MOVIES) {
                fileDirName = FILE_MOVIES;
            } else if (fileEnum == FileInEnum.PICTURES) {
                fileDirName = FILE_PICTURES;
            } else if (fileEnum == FileInEnum.MUSIC) {
                fileDirName = FILE_MUSIC;
            } else {
                fileDirName = FILE_FILE;
            }
            File file = new File(getRealCacheDir(), fileDirName);
            if (!Util.fileIsExists(file)) {
                file.mkdirs();
            }
            return file;
        }

        //获取APP内部存储文件系统上的目录(文件名一般默认为:files,该文件可见)
        public static File getPrivatePackAgeDir(FileInEnum fileEnum) {
            //mContext.getFilesDir()(与缓存目录在同一目录下,同一级别,文件名为:files):
            //如果希望将应用程序私有的文件保存在外部存储器上,可以通过调用getExternalFilesDir()获取特定于应用程序的目录
            //并传递一个表示目录类型的名称。以这种方式创建的每个目录都被添加到一个父目录中,
            //该目录封装了应用程序的所有外部存储文件,当用户卸载应用程序时,系统会清除这些文件。
            //如果预定义的子目录名都不适合您的文件,那么可以调用getExternalFilesDir()并传递null或者“”。这将返回应用程序在外部存储上的私有目录的根目录。
            String fileDirName;
            if (fileEnum == FileInEnum.MOVIES) {
                fileDirName = FILE_MOVIES;
            } else if (fileEnum == FileInEnum.PICTURES) {
                fileDirName = FILE_PICTURES;
            } else if (fileEnum == FileInEnum.MUSIC) {
                fileDirName = FILE_MUSIC;
            } else {
                fileDirName = ""; //默认为files文件
            }
            File externalFilesDir = getRealPackAgeDir(fileDirName);
            if (TextUtils.isEmpty(fileDirName)) {
                File file = new File(externalFilesDir, FILE_FILE);
                if (!Util.fileIsExists(file)) {
                    file.mkdirs();
                }
                return file;
            } else if (!Util.fileIsExists(externalFilesDir)) {
                externalFilesDir.mkdirs();
            }
            return externalFilesDir;
        }

    }

    /**
     * 将一个文件保存到APP外部公共相关目录
     */
    private static class FilePublicOutUtils {

        //保存到公共目录
        public static Uri getPublicDir(FileInEnum fileEnum, String fileName) {
            //如果你想将文件保存在外部存储器,其他应用程序应该可以访问,使用以下api之一:
            //如果要保存照片、音频文件或视频剪辑,请使用MediaStore API。
            //如果要保存任何其他文件,比如PDF文档,请使用ACTION_CREATE_DOCUMENT intent,它是存储访问框架的一部分。
            //如果您想要在媒体扫描器中隐藏文件,请在特定于应用程序的目录中包含一个名为.nomedia的空文件(请注意文件名中的点前缀)。
            // 这可以防止媒体扫描器读取您的媒体文件并通过MediaStore API将它们提供给其他应用程序。
            //Primary directory sdf not allowed for content://media/external/images/media; allowed directories are [DCIM, Pictures]
            ContentValues contentValues = new ContentValues();
            ContentResolver resolver = ContextUtils.Companion.getApp().getContentResolver();
            long time = System.currentTimeMillis() / 1000;
            String name = TextUtils.isEmpty(fileName) ? String.valueOf(System.currentTimeMillis()) : fileName;
            if (fileEnum == FileInEnum.MOVIES) {
                contentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
                    contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, FILE_MOVIES + File.separator + FILE_PUBLIC);
                } else {
                    contentValues.put(MediaStore.Video.VideoColumns.IS_PRIVATE, 0);
                }
                contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, name);
                contentValues.put(MediaStore.Video.Media.DATE_ADDED, time);
                return resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
            } else if (fileEnum == FileInEnum.PICTURES) {
                contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    contentValues.put(MediaStore.Images.Media.IS_PENDING, 0);
                    contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, FILE_PICTURES + File.separator + FILE_PUBLIC);
                } else {
                    contentValues.put(MediaStore.Images.ImageColumns.IS_PRIVATE, 0);
                }
                contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, name);
                contentValues.put(MediaStore.Images.Media.DATE_ADDED, time);
                return resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
            } else if (fileEnum == FileInEnum.MUSIC) {
                contentValues.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mp3");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    contentValues.put(MediaStore.Audio.Media.IS_PENDING, 0);
                    contentValues.put(MediaStore.Audio.Media.RELATIVE_PATH, FILE_MUSIC + File.separator + FILE_PUBLIC);
                }
                contentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, name);
                contentValues.put(MediaStore.Audio.Media.DATE_ADDED, time);
                return resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues);
            } else {
                throw new NoSuchMethodError("No corresponding type was found");
            }
        }
    }


    /**
     * 保存文件
     */
    public static class FileWriteUtils {

        //将图片bitmap保存到本地
        public static boolean writeBitmapFromUri(Uri uri, Bitmap bitmap) {
            if (null == uri || null == bitmap) {
                return false;
            }
            OutputStream outputStream;
            try {
                outputStream = ContextUtils.Companion.getApp().getContentResolver().openOutputStream(uri);
                if (null != outputStream) {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
                    outputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            return true;
        }

        //将一个InputStream里面的数据写入文件中
        public static boolean writeFileFromInput(File file, InputStream input) {
            OutputStream output = null;
            try {
                output = new FileOutputStream(file);
                byte[] buffer = new byte[1024];
                int offset;
                while ((offset = input.read(buffer)) != -1) {
                    output.write(buffer, 0, offset);
                }
                output.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != output) {
                    try {
                        output.close();
                        return true;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return false;
        }

        public static void writeInFile(File file, String fileContents) {
            FileOutputStream outputStream;
            try {
                outputStream = new FileOutputStream(file);
                outputStream.write(fileContents.getBytes());
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

使用方法如:

	//glide缓存配置
	 override fun applyOptions(
        context: Context,
        builder: GlideBuilder
  	  ) {
     	   val diskCacheSizeBytes = 1024 * 1024 * 100
     	   val appStorageFile = getAppStorageInFile(
         	   FileUtils.StorageInEnum.APP_IN_PACKAGE,
         	   FileUtils.FileInEnum.FILE
      	  )
     	   if (null != appStorageFile) {
          	  builder.setDiskCache(
              	  DiskLruCacheFactory(
                    appStorageFile.absolutePath,
                    "GlideCache",
                    diskCacheSizeBytes.toLong()
                )
            )
        }
    }

	/**
	 * 保存图片到公共文件的调用方法
	 */
	fun saveImage(view: View) {
    	val bitmap = QMUIDrawableHelper.createBitmapFromView(view)
    	val publicUri = FileUtils.getPublicOutUri(FileUtils.FileInEnum.PICTURES)
    	publicUri?.apply {
        	val isWriteComplete = FileUtils.FileWriteUtils.writeBitmapFromUri(this, bitmap)
        	if (isWriteComplete) {
            	showToast("保存成功!")
        	} else {
            	showToast("保存失败,请重新尝试!")
        	}
    	}
	}
	
	/**
	 *获取缓存大小
	 */
	val cacheSize =  FileUtils.Util.getFilSizeText()
	tvText.text = cacheSize
	
	/**
	 *清除缓存
	 */
	FileUtils.Util.clearCache()
	tvText.text = cacheSize//或直接设置为OB
	showTipDialog("清理干净了")


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值