Android 7.0以上系统获取文件或图片拿不到正确路径,报错column-data-does-not-exist

注:本方法也可解决获取相册图片拿不到正确路径问题。

我们项目的使用场景,手机qq打开文件,选择其他打开方式,选择我们自己的应用打开,通过intent.getData()获取文件地址,后来发现在Android7.0之后的版本,获取到的地址不正确,说文件不存在。日志报错column-data-does-not-exist,

经过一天的折腾,终于在网上找到了一些零碎的知识拼接成了解决办法,具体如下:

判断版本获取路径的方式,在拿到uri之后进行版本判断大于等于24(即Android7.0)用最新的获取路径方式,否则用你之前的方式,

String picPath;
if (Build.VERSION.SDK_INT >= 24) {
    picPath = getFilePathFromURI(this,uri);
} else {
    picPath = RealPathFromUriUtils.getRealPathFromUri(this,uri);
}

private String getFilePathFromURI(Context context, Uri contentUri) {
    File rootDataDir = context.getFilesDir();
    String fileName = getFileName(contentUri);
    if (!TextUtils.isEmpty(fileName)) {
        File copyFile = new File(rootDataDir + File.separator + fileName + ".jpg");
        copyFile(context, contentUri, copyFile);
        return copyFile.getAbsolutePath();
    }
    return null;
}

private String getFileName(Uri uri) {
    if (uri == null) return null;
    String fileName = null;
    String path = uri.getPath();
    int cut = path.lastIndexOf('/');
    if (cut != -1) {
        fileName = path.substring(cut + 1);
    }
    return System.currentTimeMillis() + fileName;
}

private void copyFile(Context context, Uri srcUri, File dstFile) {
    try {
        InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
        if (inputStream == null) return;
        OutputStream outputStream = new FileOutputStream(dstFile);
        copyStream(inputStream, outputStream);
        inputStream.close();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private int copyStream(InputStream input, OutputStream output) throws Exception, IOException {
    final int BUFFER_SIZE = 1024 * 2;
    byte[] buffer = new byte[BUFFER_SIZE];
    BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
    BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
    int count = 0, n = 0;
    try {
        while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
            out.write(buffer, 0, n);
            count += n;
        }
        out.flush();
    } finally {
        try {
            out.close();
        } catch (IOException e) {
        }
        try {
            in.close();
        } catch (IOException e) {
        }
    }
    return count;
}

RealPathFromUriUtils工具类:

import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

/**
 * Created by W.H.K
 * on 2019/5/20
 */
public class RealPathFromUriUtils {
    /**
     * 根据Uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    public static String getRealPathFromUri(Context context, Uri uri) {
        int sdkVersion = Build.VERSION.SDK_INT;
        if (sdkVersion >= 19) { // api >= 19
            return getRealPathFromUriAboveApi19(context, uri);
        } else { // api < 19
            return getRealPathFromUriBelowAPI19(context, uri);
        }
    }

    /**
     * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
        return getDataColumn(context, uri, null, null);
    }

    /**
     * 适配api19及以上,根据uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    @SuppressLint("NewApi")
    private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
        String filePath = null;
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document类型的 uri, 则通过document id来进行处理
            String documentId = DocumentsContract.getDocumentId(uri);
            if (isMediaDocument(uri)) { // MediaProvider
                // 使用':'分割
                String id = documentId.split(":")[1];

                String selection = MediaStore.Images.Media._ID + "=?";
                String[] selectionArgs = {id};
                filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
            } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                filePath = getDataColumn(context, contentUri, null, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // 如果是 content 类型的 Uri
            filePath = getDataColumn(context, uri, null, null);
        } else if ("file".equals(uri.getScheme())) {
            // 如果是 file 类型的 Uri,直接获取图片对应的路径
            filePath = uri.getPath();
        }
        return filePath;
    }

    /**
     * 获取数据库表中的 _data 列,即返回Uri对应的文件路径
     *
     * @return
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String path = null;

        String[] projection = new String[]{MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                path = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            if (cursor != null) {
                cursor.close();
            }
        }
        return path;
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is MediaProvider
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is DownloadsProvider
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }
}

希望能解决你们遇到的问题。

### 关于 `gt-data` 文件未找到错误的解决方案 当遇到类似于 `gt-data not found` 的错误时,通常表示程序尝试访问某个文件资源失败。这种问题可能由多种原因引起,包括权限不足、路径配置不正确、环境变量缺失其他外部依赖项不可用。 以下是针对该问题的具体分析和解决方法: #### 1. **确认文件是否存在** 首先需要验证目标文件 `gt-data` 是否确实存在于指定位置。可以通过命令行工具检查文件的存在状态以及其属性。 ```bash ls -l /path/to/gt-data ``` 如果文件不存在,则需重新生成下载此文件,并将其放置到正确的目录下[^2]。 --- #### 2. **检查文件路径配置** 错误可能是由于程序中指定了错误的路径所致。如果应用程序允许自定义数据存储路径,请确保已正确设置相关参数。例如,在 MySQL 中可能会因为路径错误引发类似的文件丢失提示: ```sql LOAD DATA INFILE '/var/lib/mysql-files/gt-data.csv' INTO TABLE my_table; ``` 上述 SQL 命令中的路径 `/var/lib/mysql-files/` 是一个常见的默认路径;如果不是标准路径,请调整为实际存放的位置。 --- #### 3. **校验读写权限** 即使文件存在,但如果运行进程缺乏足够的权限来访问它,也会触发此类异常。可以使用以下命令授予必要的权限给对应用户组者服务账户: ```bash chmod 644 /path/to/gt-data chown mysql:mysql /path/to/gt-data ``` 此外还需注意操作系统层面的安全策略(SELinux/AppArmor),它们有时会阻止某些操作即使表面上看起来有适当许可也无济于事[^4]。 --- #### 4. **排查日志记录** 查阅应用的日志可以帮助定位更深层次的原因。大多数情况下,详细的诊断信息会被记录下来供开发者审查。对于数据库管理系统而言,查看错误日志尤为重要: ```bash tail -f /var/log/mysqld.log ``` 者如果是其他类型的服务器端脚本抛出了这个问题,则应该寻找相应的后台处理记录文件进行深入探究[^1]。 --- #### 5. **考虑网络共享场景下的特殊需求** 若涉及跨机器挂载磁盘单元是通过NFS等方式实现资源共享的情况下,还需要额外关注远程连接稳定性及时延影响等因素是否干扰到了正常加载过程[^3]。 --- ```python import os def check_file(file_path): """Utility to verify existence & accessibility.""" if not os.path.exists(file_path): raise FileNotFoundError(f"The specified file {file_path} does NOT exist.") elif not os.access(file_path, os.R_OK | os.W_OK): raise PermissionError(f"Lacking proper access rights on {file_path}.") check_file("/absolute/path/to/gt-data") print("File verification passed successfully!") ``` 上述 Python 脚本可用于自动化执行基本健康状况测试并报告潜在障碍点所在之处。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值