Android 获取文件,图片,视频大小

本文介绍了一个用于计算文件或文件夹大小的Java工具类。该工具类提供了多种方法来获取文件大小,并能自动选择合适的单位(B、KB、MB、GB)。此外,还支持指定单位进行精确转换。

直接上代码

public class FileSizeUtil {

    private static final String TAG=FileSizeUtil.class.getSimpleName();

    public static final int SIZETYPE_B = 1;//获取文件大小单位为B的double值
    public static final int SIZETYPE_KB = 2;//获取文件大小单位为KB的double值
    public static final int SIZETYPE_MB = 3;//获取文件大小单位为MB的double值
    public static final int SIZETYPE_GB = 4;//获取文件大小单位为GB的double值

    /**
     * 获取文件指定文件的指定单位的大小
     *
     * @param filePath 文件路径
     * @param sizeType 获取大小的类型1为B、2为KB、3为MB、4为GB
     * @return double值的大小
     */
    public static double getFileOrFilesSize(String filePath, int sizeType) {
        File file = new File(filePath);
        long blockSize = 0;
        try {
            if (file.isDirectory()) {
                blockSize = getFileSizes(file);
            } else {
                blockSize = getFileSize(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG,"获取文件大小失败!");
        }
        return FormetFileSize(blockSize, sizeType);
    }

    /**
     * 调用此方法自动计算指定文件或指定文件夹的大小
     *
     * @param filePath 文件路径
     * @return 计算好的带B、KB、MB、GB的字符串
     */
    public static String getAutoFileOrFilesSize(String filePath) {
        File file = new File(filePath);
        long blockSize = 0;
        try {
            if (file.isDirectory()) {
                blockSize = getFileSizes(file);
            } else {
                blockSize = getFileSize(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG,"获取文件大小失败!");
        }
        return FormetFileSize(blockSize);
    }

    /**
     * 获取指定文件大小
     *
     * @param file
     * @return
     * @throws Exception
     */
    private static long getFileSize(File file) throws Exception {
        long size = 0;
        if (file.exists()) {
            FileInputStream fis = null;
            fis = new FileInputStream(file);
            size = fis.available();
        } else {
            file.createNewFile();
            Log.e(TAG,"获取文件大小不存在!");
        }
        return size;
    }

    /**
     * 获取指定文件夹
     *
     * @param f
     * @return
     * @throws Exception
     */
    private static long getFileSizes(File f) throws Exception {
        long size = 0;
        File flist[] = f.listFiles();
        for (int i = 0; i < flist.length; i++) {
            if (flist[i].isDirectory()) {
                size = size + getFileSizes(flist[i]);
            } else {
                size = size + getFileSize(flist[i]);
            }
        }
        return size;
    }

    /**
     * 转换文件大小
     *
     * @param fileS
     * @return
     */
    private static String FormetFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (fileS == 0) {
            return wrongSize;
        }
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + "B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + "KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + "MB";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + "GB";
        }
        return fileSizeString;
    }

    /**
     * 转换文件大小,指定转换的类型
     *
     * @param fileS
     * @param sizeType
     * @return
     */
    private static double FormetFileSize(long fileS, int sizeType) {
        DecimalFormat df = new DecimalFormat("#.00");
        double fileSizeLong = 0;
        switch (sizeType) {
            case SIZETYPE_B:
                fileSizeLong = Double.valueOf(df.format((double) fileS));
                break;
            case SIZETYPE_KB:
                fileSizeLong = Double.valueOf(df.format((double) fileS / 1024));
                break;
            case SIZETYPE_MB:
                fileSizeLong = Double.valueOf(df.format((double) fileS / 1048576));
                break;
            case SIZETYPE_GB:
                fileSizeLong = Double.valueOf(df.format((double) fileS / 1073741824));
                break;
            default:
                break;
        }
        return fileSizeLong;
    }
}

<think>我们已知用户的需求是:在Android开发中使用Cursor读取视频图片文件,并获取文件大小。 根据提供的引用,我们可以从两个方面获取文件大小: 1. 使用ContentResolver查询时,可以直接查询MediaStore中存储的文件大小字段(例如MediaStore.Images.Media.SIZE用于图片,MediaStore.Video.Media.SIZE用于视频)。 2. 如果通过Cursor获取文件的路径(如MediaStore.Images.Media.DATA或MediaStore.Video.Media.DATA),我们也可以使用File对象来获取文件大小,但这种方法可能不如直接使用SIZE字段高效,因为需要额外的I/O操作。 但是,根据用户的要求,他们希望使用Cursor来读取,因此我们优先考虑通过Cursor直接获取文件大小(即查询SIZE字段)。 注意:引用[1]中展示了如何通过ContentResolver查询图片大小(MediaStore.Images.Media.SIZE)。同样,对于视频,我们可以使用MediaStore.Video.Media.SIZE。 步骤: 1. 确定要查询的是图片还是视频(或者两者都要?)。用户的问题中同时提到了视频图片。 2. 构建查询:根据媒体类型(图片视频)使用不同的Uri和字段。 3. 在投影(projection)中包含大小字段(SIZE)和路径字段(DATA,以防需要备用方法获取大小)。 4. 执行查询,然后从Cursor中读取大小。 然而,需要注意的是,MediaStore中存储的SIZE字段可能不是最新的(例如,如果文件被修改了,但媒体库未更新)。因此,如果对准确性要求高,可以通过获取文件路径然后使用File来获取大小,但这样会牺牲一些性能。 下面分别给出获取图片视频文件大小的示例代码: 示例1:获取图片文件大小 使用MediaStore.Images.Media.EXTERNAL_CONTENT_URI查询,并获取MediaStore.Images.Media.SIZE。 示例2:获取视频文件大小 使用MediaStore.Video.Media.EXTERNAL_CONTENT_URI查询,并获取MediaStore.Video.Media.SIZE。 但是,用户可能希望一个方法同时处理图片视频?那么我们需要分开查询,或者根据Uri的类型来动态处理。这里我们分开处理。 另外,引用[2]中展示了如何查询图片文件列表,其中用到了DATA字段(即路径)。我们可以参考这个来获取路径,但我们现在主要关注大小。 下面提供两个方法分别获取图片视频大小,以及一个通用的方法(根据传入的Uri和字段名,但需要知道是图片还是视频,或者我们可以通过Uri来区分)。 不过,为了简单和清晰,我们先分别写两个方法。 注意:在Android Q(10)及以上,直接访问文件路径可能受到限制,所以优先使用ContentResolver和MediaStore提供的方式。 代码示例: 1. 获取图片文件大小(通过Cursor) ```java public long getImageSize(Uri imageUri) { long size = 0; Cursor cursor = null; try { cursor = getContentResolver().query( imageUri, new String[]{MediaStore.Images.Media.SIZE}, null, null, null ); if (cursor != null && cursor.moveToFirst()) { size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } return size; } ``` 2. 获取视频文件大小(通过Cursor) ```java public long getVideoSize(Uri videoUri) { long size = 0; Cursor cursor = null; try { cursor = getContentResolver().query( videoUri, new String[]{MediaStore.Video.Media.SIZE}, null, null, null ); if (cursor != null && cursor.moveToFirst()) { size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } return size; } ``` 但是,上述方法需要传入具体文件的Uri。如果我们要查询多个文件(比如获取所有图片视频文件大小),我们可以使用类似引用[2]的方法,在查询列表时就把大小字段包含进去。 例如,查询所有图片文件的信息(包括大小): ```java public List<ImageItem> getImageList() { List<ImageItem> imageList = new ArrayList<>(); Cursor cursor = null; try { cursor = getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{ MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.SIZE, MediaStore.Images.Media.DATA }, null, null, MediaStore.Images.Media.DATE_MODIFIED + " DESC" ); if (cursor != null && cursor.moveToFirst()) { do { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)); String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)); long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)); String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)); // 创建一个ImageItem对象,或者直接使用这些数据 // 将数据添加到列表 } while (cursor.moveToNext()); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } return imageList; } ``` 同样,对于视频,只需将Uri改为MediaStore.Video.Media.EXTERNAL_CONTENT_URI,并使用视频的字段。 但是,如果我们在查询列表时已经获取大小,那么就可以直接使用。 注意事项: - SIZE字段的单位是字节(byte)。 - 有些情况下,SIZE字段可能为0(比如媒体库未更新),这时我们可以通过获取文件的Uri,然后使用ContentResolver的openFileDescriptor来获取实际大小(或者使用File,但Android Q以上需要谨慎使用文件路径)。 如果SIZE字段为0,我们可以尝试通过文件路径获取(在Android Q以下)或者通过Uri打开文件描述符来获取大小。 通过文件描述符获取文件大小的方法(适用于Android Q及以上,因为直接使用文件路径可能没有权限): ```java public long getFileSizeFromUri(Uri uri) { ContentResolver contentResolver = getContentResolver(); try (ParcelFileDescriptor fileDescriptor = contentResolver.openFileDescriptor(uri, "r")) { if (fileDescriptor != null) { long size = fileDescriptor.getStatSize(); return size; } } catch (IOException e) { e.printStackTrace(); } return 0; } ``` 因此,我们可以结合两种方式:先尝试从Cursor中获取SIZE字段,如果获取到的大小为0,再使用文件描述符的方式获取。 总结回答用户的问题: 用户可以通过在查询时包含MediaStore.Images.Media.SIZE(图片)或MediaStore.Video.Media.SIZE(视频)来直接从Cursor中获取文件大小。如果获取大小为0,可能需要使用其他方法(如通过文件描述符)来获取。 下面是一个综合示例,获取一个Uri(可能是图片视频)对应的文件大小: ```java public long getMediaFileSize(Uri mediaUri) { // 首先尝试通过查询SIZE字段获取 long size = 0; Cursor cursor = null; try { // 我们不知道是图片还是视频,所以需要根据Uri的authority或者类型判断?但这里我们假设已经知道是图片视频,或者我们可以通过两种方式查询? // 但是,如果不知道,我们可以尝试先查询图片的SIZE,再查询视频的SIZE?这样效率低。 // 实际上,我们通常知道这个Uri是来自图片还是视频(因为查询时已经区分了),所以这里我们建议用户分开处理图片视频。 // 如果无法区分,我们可以尝试查询两种类型(不推荐,因为效率低且复杂)。 // 因此,这里我们假设传入的Uri是图片视频的Uri,并且我们不知道具体类型,那么我们可以尝试获取其MIME类型,但这样更复杂。 // 为了简单,我们假设用户知道是图片还是视频,所以这里我们只提供针对已知类型的方法。如果用户需要通用方法,可能需要额外处理。 // 实际上,我们可以通过ContentResolver.getType(uri)来获取MIME类型,然后判断是图片还是视频。 String mimeType = getContentResolver().getType(mediaUri); if (mimeType != null) { String mediaType = null; if (mimeType.startsWith("image/")) { mediaType = "image"; } else if (mimeType.startsWith("video/")) { mediaType = "video"; } if (mediaType != null) { String columnName = mediaType.equals("image") ? MediaStore.Images.Media.SIZE : MediaStore.Video.Media.SIZE; cursor = getContentResolver().query( mediaUri, new String[]{columnName}, null, null, null ); if (cursor != null && cursor.moveToFirst()) { size = cursor.getLong(0); } } } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } // 如果通过Cursor获取大小为0,再尝试通过文件描述符获取 if (size <= 0) { size = getFileSizeFromUri(mediaUri); // 使用上面定义的getFileSizeFromUri方法 } return size; } ``` 但是,这种方法在查询时可能会因为Uri的类型不同而需要不同的列名,而且通过MIME类型判断可能不够全面(例如,用户可能使用其他类型的Uri)。因此,更稳健的做法是直接使用文件描述符的方法,但这样每次都要打开文件,效率较低。 因此,根据用户的具体场景: 如果是在查询媒体文件列表时,建议在查询时就把SIZE字段包含进去,这样效率最高。 如果是针对单个已知Uri(且知道是图片视频),则可以使用对应的方法。 最后,考虑到性能,在批量查询时优先使用Cursor获取SIZE字段,而对于单个文件,如果SIZE字段不可用(为0)再使用文件描述符。 根据引用[1]和引用[2],我们提供了上述方法。 相关问题: 1. 在Android Q及以上,如何安全地获取文件大小? 2. 如何更新MediaStore中的文件大小信息? 3. 使用Cursor查询媒体文件时,如何避免性能问题?</think>在 Android 开发中,通过 `Cursor` 读取媒体文件图片/视频)并获取文件大小,可以使用 `MediaStore` API 结合 `ContentResolver`。以下是具体实现方法: ### 1. 获取图片文件大小 ```java public long getImageSize(Uri imageUri) { long size = 0; try (Cursor cursor = getContentResolver().query( imageUri, new String[]{MediaStore.Images.Media.SIZE}, // 查询大小字段 null, null, null )) { if (cursor != null && cursor.moveToFirst()) { int sizeIndex = cursor.getColumnIndex(MediaStore.Images.Media.SIZE); size = cursor.getLong(sizeIndex); } } catch (Exception e) { e.printStackTrace(); } return size; } ``` ### 2. 获取视频文件大小 ```java public long getVideoSize(Uri videoUri) { long size = 0; try (Cursor cursor = getContentResolver().query( videoUri, new String[]{MediaStore.Video.Media.SIZE}, // 视频大小字段 null, null, null )) { if (cursor != null && cursor.moveToFirst()) { int sizeIndex = cursor.getColumnIndex(MediaStore.Video.Media.SIZE); size = cursor.getLong(sizeIndex); } } catch (Exception e) { e.printStackTrace(); } return size; } ``` ### 3. 批量获取媒体文件信息(含大小) ```java public List<MediaFile> getMediaFiles() { List<MediaFile> files = new ArrayList<>(); // 查询图片 try (Cursor cursor = getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{ MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.SIZE, // 大小字段 MediaStore.Images.Media.DATA }, null, null, null )) { while (cursor != null && cursor.moveToNext()) { long size = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE)); String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); files.add(new MediaFile(path, size, "image")); } } // 查询视频(同理) try (Cursor cursor = getContentResolver().query( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, new String[]{...}, // 使用视频字段 null, null, null )) { // 处理视频... } return files; } ``` ### 关键点说明 1. **字段说明**: - `MediaStore.Images.Media.SIZE`:图片文件大小(字节) - `MediaStore.Video.Media.SIZE`:视频文件大小(字节) - `MediaStore.Images.Media.DATA`:文件完整路径 2. **注意事项**: - 需要运行时权限:`READ_EXTERNAL_STORAGE` - Android 10+ 需在 `AndroidManifest.xml` 添加: ```xml <application android:requestLegacyExternalStorage="true" ...> ``` - 如果 `SIZE` 字段返回 0,可能是媒体库未更新,可通过以下方法刷新: ```java MediaScannerConnection.scanFile(context, new String[]{filePath}, null, null); ``` 3. **备选方案**: 若 `SIZE` 字段不可靠,可通过文件路径获取大小: ```java File file = new File(path); long size = file.length(); ``` ### 性能优化建议 - 使用投影查询(`projection` 参数)只获取必要字段 - 用 `try-with-resources` 自动关闭 `Cursor` - 批量查询时添加 `LIMIT` 分页避免内存溢出
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值