GVKun编程网logo

重命名由android 10中的应用程序创建的Mediastore的文件。正在使用Android API 30,但在API 29中显示错误

13

在本文中,我们将给您介绍关于重命名由android10中的应用程序创建的Mediastore的文件。正在使用AndroidAPI30,但在API29中显示错误的详细内容,此外,我们还将为您提供关于An

在本文中,我们将给您介绍关于重命名由android 10中的应用程序创建的Mediastore的文件。正在使用Android API 30,但在API 29中显示错误的详细内容,此外,我们还将为您提供关于Android API 30 中的外部文件读取和写入,在 JAVA 中使用 MediaStore API、Android CRUD MediaStore API 26+、Android Media Store API 在外部存储中找不到由 Google Photo 创建的图像、Android MediaStore插入图像创建的附加文件的知识。

本文目录一览:

重命名由android 10中的应用程序创建的Mediastore的文件。正在使用Android API 30,但在API 29中显示错误

重命名由android 10中的应用程序创建的Mediastore的文件。正在使用Android API 30,但在API 29中显示错误

在这里,此renameFile(..)函数在Android API 30中正常工作。但是,在Android API 29中却无效,并显示如下错误:

java.lang.IllegalArgumentException:不允许移动内容:// media / external / file /116,这不是定义明确的集合的一部分

更新说明:

-开始-

为了使用sdk-29,我们必须使用Uri作为extUri =MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL),例如:

private static Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);

代替下面的代码。并将 MediaStore.Files.FileColumns 更新为 MediaStore.Downloads

-结束-

Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";

函数renameFile(…)

boolean renameFile(Context context, String newName, String displayName) {    try {        Long id = getIdFromDisplayName(displayName);        ContentResolver contentResolver = context.getContentResolver();        Uri mUri = ContentUris.withAppendedId(extUri, id);        ContentValues contentValues = new ContentValues();        contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);        contentResolver.update(mUri, contentValues, null, null);        contentValues.clear();        contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newName);        // contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, "files/pdf");        // contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, relativeLocation);        // contentValues.put(MediaStore.Files.FileColumns.TITLE, "SomeName");        // contentValues.put(MediaStore.Files.FileColumns.DATE_ADDED, System.currentTimeMillis() / 1000);        // contentValues.put(MediaStore.Files.FileColumns.DATE_TAKEN, System.currentTimeMillis());        contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);        contentResolver.update(mUri, contentValues, null, null);        return true;    } catch (Exception ex) {        ex.printStackTrace();    }    return false;}

函数getIdFromDisplayName(…)

@RequiresApi(api = Build.VERSION_CODES.Q)Long getIdFromDisplayName(String displayName) {    String[] projection;    projection = new String[]{MediaStore.Files.FileColumns._ID};    // TODO This will break if we have no matching item in the MediaStore.    Cursor cursor = getContentResolver().query(extUri, projection,            MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);    assert cursor != null;    cursor.moveToFirst();    if (cursor.getCount() > 0) {        int columnIndex = cursor.getColumnIndex(projection[0]);        long fileId = cursor.getLong(columnIndex);        cursor.close();        return fileId;    }    return null;}

答案1

小编典典

java.lang.IllegalArgumentException:不允许移动内容:// media / external / file /
116,这不是定义明确的集合的一部分

因此,如果您使用集合,则不适用于Android Q;

Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);

但允许“定义明确的集合”,例如:

Uri extUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);// Use  "Pictures/MyFolder" for RELATIVE_PATH

我留给您查找其他定义明确的集合。

为什么这仅适用于Android Q我不知道。

您可以在以下Java文件中看到该消息:https
:
//android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/MediaProvider.java

引用:

     // We only support movement under well-defined collections        switch (match) {            case AUDIO_MEDIA_ID:            case VIDEO_MEDIA_ID:            case IMAGES_MEDIA_ID:            case DOWNLOADS_ID:                break;            default:                throw new IllegalArgumentException("Movement of " + uri                        + " which isn''t part of well-defined collection not allowed");        }

如果重命名失败,请使用SAF(如前所述)。如何在仅知道媒体内容Uri的Android中重命名文件

Android API 30 中的外部文件读取和写入,在 JAVA 中使用 MediaStore API

Android API 30 中的外部文件读取和写入,在 JAVA 中使用 MediaStore API

如何解决Android API 30 中的外部文件读取和写入,在 JAVA 中使用 MediaStore API?

我对新的 Google 政策有疑问。我正在尝试找到一种无需 MANAGE_EXTERNAL_STORAGE 权限即可读取或写入 txt 文件的方法。问题是: MediaStore API 可用于写入或读取文件,但我只能读取稍后由应用程序创建的文件。就我而言,外部软件通过 USB 连接使用 adb.exe 将数据上传到手机,并且该应用程序使用这些数据。 因为它不是由应用程序创建的,所以我收到以下示例的“FileNotFoundException”“权限被拒绝”错误消息。应用程序创建的文件是什么样的标志?我可以授予外部文件这个权利吗?

   if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){
            ContentValues contentValues= new ContentValues();
            String datfile = null;
            contentValues.put(MediaStore.Files.FileColumns.disPLAY_NAME,"ac.dat");
            contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE,"");
            contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH,Environment.DIRECTORY_DOCUMENTS+dir);
            Uri uri = context.getContentResolver().insert(MediaStore.Files.getContentUri("external"),contentValues);

            InputStream inputStream = context.getContentResolver().openInputStream(uri);
            
            int read = 0;
            int bufferSize = 1024;
            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                datfile = new String(buffers);
            }

            inputStream.close();
        }

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Android CRUD MediaStore API 26+

Android CRUD MediaStore API 26+

如何解决Android CRUD MediaStore API 26+?

我有一个 API26+ 的应用程序

Android 10 及更高版本 (API29+) 应使用 MediaStore 来访问文件,而不是 Environment.getExternalStoragePublicDirectory

通常在创建 if-block 时会产生新的方法

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
    // deprecated code
} else {
    // new approach
}

但是:

  • MediaStorage 使用 Uri 请求文件。 API28 及以下版本使用 FileString 作为文件路径
  • 使用 MediaStore 不需要手动创建文件夹。如果 API 28 及以下版本不存在,则应创建一个文件夹。
  • 删除文件需要用户与 MediaStore 交互。

CRUD:

  • 创建:需要为任何 API 在文件中写入数据OutputStream。这可以通过 if else
  • 实现
  • 读取:如何创建读取文件的通用方法,其中 API 29+ 需要 Uri,API28- 需要 File|String 才能访问文件?
  • 更新:首先读取以检查是否存在,然后创建以获取OutputStream
  • 删除:如何使用 MediaStore 创建批量确认?

是否可以通过 API26+ 使用 MediaStorage

如果是,如何? API29中首先添加了许多属性

解决方法

经过一些自己的研究和测试,我找到了同时使用 MediaStore 和旧设备的方法。

首先需要一些辅助类:

使用 FileType,我们可以同时在应用程序中支持不同的文件类型。

public enum FileType {

    File(Environment.DIRECTORY_DOCUMENTS,Constants.VERSION_29_ABOVE ? MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) : null,"text/plain"),Download(Environment.DIRECTORY_DOWNLOADS,Constants.VERSION_29_ABOVE ? MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) : null,Image(Environment.DIRECTORY_PICTURES,Constants.VERSION_29_ABOVE ? MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null,"image/jpeg"),Audio(Environment.DIRECTORY_MUSIC,Constants.VERSION_29_ABOVE ? MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null,"audio/mpeg"),Video(Environment.DIRECTORY_MOVIES,Constants.VERSION_29_ABOVE ? MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null,"video/mpeg");

    private final String directory;
    private final Uri contentUri;
    private String mimeType;

    FileType(String directory,Uri contentUri,String mimeType) {
        this.directory = directory;
        this.contentUri = contentUri;
        this.mimeType = mimeType;
    }

    public String getDirectory() {
        return directory;
    }

    public Uri getContentUri() {
        return contentUri;
    }

    public String getMimeType() {
        return mimeType;
    }

    public void setMimeType(String mimeType) {
        this.mimeType = mimeType;
    }
}

使用 setMimeType 我们可以更改当前文件扩展名并仍然使用其他设置

我们需要简单的回调类来得到不同的结果

public interface ObjectCallback<T> {

    void result(T object);
}

当我们想在文件中写入一些数据时,我们需要一个 OutputStream

使用内部存储,获取文件的方式没有改变

/**
 * opens OutputStream to write data to file
 *
 * @param context    activity context
 * @param fileName   relative file name
 * @param fileType   file type to get folder specific values for access
 * @param fileStream callback with file output stream to requested file
 * @return true if output stream successful opened,false otherwise
 */
public boolean openOutputStream(Context context,String fileName,FileType fileType,ObjectCallback<OutputStream> fileStream) {
    File internalFolder = context.getExternalFilesDir(fileType.getDirectory());
    File absFileName = new File(internalFolder,fileName);

    try {
        FileOutputStream fOut = new FileOutputStream(absFileName);
        fileStream.result(fOut);
    } catch (Exception e) {
        e.printStackTrace();

        return false;
    }

    return true;
}

通过外部存储,在 API 28- 和 API 29+ 上访问文件的方式完全不同。 在 API 28 上,我们可以只使用一个文件。 在 API 29+ 上,我们应该首先检查文件是否已经存在。如果它(比如 text.txt)存在并且我们将创建 ContentResolver.insert,它将创建 text-1.txt 并且在最坏的情况下(无限循环)可以快速填满整个智能手机存储。

/**
 * @param context  application context
 * @param fileName relative file name
 * @return uri to file or null if file not exist
 */
public Uri getFileUri(Context context,String fileName) {
    // remove folders from file name
    fileName = fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName;

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        // Deprecated in API 29
        File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),Constants.PUBLIC_STORAGE_FOLDER);

        File file = new File(storageDir,fileName);

        return file.exists() ? Uri.fromFile(file) : null;
    } else {
        String folderName = Environment.DIRECTORY_PICTURES + File.separator + Constants.PUBLIC_STORAGE_FOLDER + File.separator;

        // get content resolver that can interact with public storage
        ContentResolver resolver = context.getContentResolver();

        String selection = MediaStore.MediaColumns.RELATIVE_PATH + "=?";
        String[] selectionArgs = new String[]{folderName};

        Cursor cursor = resolver.query(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL),null,selection,selectionArgs,null);

        Uri uri = null;

        if (cursor.getCount() > 0) {
            while (cursor.moveToNext()) {
                String itemFileName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));

                if (itemFileName.equals(fileName)) {
                    long id = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID));

                    uri = ContentUris.withAppendedId(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL),id);

                    break;
                }
            }
        }

        cursor.close();

        return uri;
    }
}

/**
 * opens OutputStream to write data to file
 *
 * @param context    activity context
 * @param fileName   relative file name
 * @param fileType   file type to get folder specific values for access
 * @param fileStream callback with file output stream to requested file
 * @return true if output stream successful opened,ObjectCallback<OutputStream> fileStream) {
    // remove folders from file name
    fileName = fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName;

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),Constants.PUBLIC_STORAGE_FOLDER);

        if (!storageDir.exists() && !storageDir.mkdir()) {
            // directory for file not exists and not created. return false
            return false;
        }

        File file = new File(storageDir,fileName);

        try {
            FileOutputStream fOut = new FileOutputStream(file);
            fileStream.result(fOut);
        } catch (Exception e) {
            e.printStackTrace();

            return false;
        }
    } else {
        // get content resolver that can interact with public storage
        ContentResolver resolver = context.getContentResolver();

        // always check first if file already exist
        Uri existFile = getFileUri(context,fileName);

        if (existFile == null) {
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.MIME_TYPE,fileType.getMimeType());
            // absolute folder name
            values.put(MediaStore.MediaColumns.RELATIVE_PATH,fileType.getDirectory() + File.separator + Constants.PUBLIC_STORAGE_FOLDER);
            // file name
            values.put(MediaStore.MediaColumns.DISPLAY_NAME,fileName);

            // create uri to the file. If folder not exists,it would be created automatically
            Uri uri = resolver.insert(fileType.getContentUri(),values);

            // open stream from uri and write data to file
            try (OutputStream outputStream = resolver.openOutputStream(uri)) {
                fileStream.result(outputStream);

                // end changing of file
                // when this point reached,no exception was thrown and file write was successful
                values.put(MediaStore.MediaColumns.IS_PENDING,false);
                resolver.update(uri,values,null);
            } catch (Exception e) {
                e.printStackTrace();

                if (uri != null) {
                    // Don''t leave an orphan entry in the MediaStore
                    resolver.delete(uri,null);
                }

                return false;
            }
        } else {
            // open stream from uri and write data to file
            try (OutputStream outputStream = resolver.openOutputStream(existFile)) {
                fileStream.result(outputStream);
            } catch (Exception e) {
                e.printStackTrace();

                // Don''t leave an orphan entry in the MediaStore
                resolver.delete(existFile,null);

                return false;
            }
        }
    }

    return true;
}

可以在所有设备和不同存储空间上以相同的方式打开 InputStream

删除文件:

  • internal 仍然可以在每个 API 上使用 file.delete 删除
  • 使用 API29+ 的外部存储需要用户交互才能删除某些文件

文件提供者

要使用 Intent 来显示一些图片、裁剪图片或其他什么,我们使用 setDataAndType

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(photoUri,"image/*");
// allow to read the file
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

在某些情况下我们需要 FileProvider。特别:

enter image description here

要显示使用应用程序创建的外部文件,photoUri 会以这种方式显示

 Uri photoUri = Constants.VERSION_29_ABOVE ? uriToFile : 
      FileProvider.getUriForFile(context,context.getApplicationContext().getPackageName() + ".provider",new File(uriToFile.getPath()));

Android Media Store API 在外部存储中找不到由 Google Photo 创建的图像

Android Media Store API 在外部存储中找不到由 Google Photo 创建的图像

如何解决Android Media Store API 在外部存储中找不到由 Google Photo 创建的图像?

我尝试实现一个图库应用程序,该应用程序还显示按其包含目录分组的所有本地存储图像文件。 为此,我构建了 MediaStore API。

我的代码找不到本地图像目录,如果这些目录和图像文件是由 Google 相册创建的。 但是,如果我使用 Google 文件在受影响的目录中复制/移动/创建图像文件,那么我的应用会找到该图像。

我做错了什么?

注意:我说的是外部存储上 Pictures/ 目录下的真实文件系统目录。我不是在谈论 Google 相册在云中创建的相册。 根据 developer documentation,MediaStore API 应在 Pictures/ 目录下找到所有图像。

图像,包括照片和屏幕截图,存储在 DCIM/ 和 Pictures/ 目录中。系统会将这些文件添加到 MediaStore.Images 表中。

简化代码:

清单

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

简化的数据类

public class LocalFolder {
  public final long id;
  public final Uri coverUri;

  public LocalFolder( final long id,final Uri coverUri ) {
    this.id = id;
    this.coverUri = coverUri;
  }
}

为内部数据库播种的简化代码

protected TreeMap< Long,LocalFolder > database;

public void run() {
  final Uri collection = ( Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ) ?
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI :
    MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);

  final String[] projection = {
    MediaStore.Images.Media._ID,MediaStore.Images.Media.BUCKET_ID };
  final Cursor cursor = contentResolver.query(
    collection,projection,null,null
  );
  if(cursor == null) return;

  // Cache column indices
  final int imageIdColumn = cursor.getColumnIndexOrThrow( MediaStore.Images.Media._ID );
  final int folderIdColumn = cursor.getColumnIndexOrThrow( MediaStore.Images.Media.BUCKET_ID );

  while( cursor.movetoNext() ) {
    // Compile all required attributes
    final long imageId = cursor.getLong( imageIdColumn );
    final long folderId =  cursor.getLong( folderIdColumn );
    final Uri coverUri = ContentUris.withAppendedId( collection,imageId );

    // If the image is contained in a folder,which already has been processed,skip
    if( database.containsKey( folderId ) )
      continue;

    // Create the folder and take the current image as cover image
    final LocalFolder localFolder = new LocalFolder( folderId,coverUri );
    database.put( folderId,localFolder );
  }
  cursor.close();
}

重现步骤:

  1. 创建一个新的共享图像文件
    1. 打开您最喜欢的网络浏览器并下载图像文件
    2. 图片文件放在共享的Downloads/目录下
  2. 上面的代码找到了图像(很好!)
  3. 使用 Google 相册将图像文件移动到基​​于文件系统的新目录中
    1. 打开 Google 相册
    2. 打开注册“图书馆”
    3. 打开相册“下载”
    4. 打开最近添加的图片
    5. 点按“设置”(右上角的点)
    6. 点按“移至文件夹”
    7. 点按“新建文件夹”
    8. 创建一个新文件夹
  4. 上面的代码没有找到图像(糟糕!)
  5. 使用 Google 文件“重新创建”图像文件
    1. 打开 Google 文件
    2. 点按汉堡菜单
    3. 点按设备
    4. 打开目录图片/
    5. 打开谷歌相册新建目录对应的子目录
    6. 长按最近添加的图片文件
    7. 移动图像文件并将图像文件移回文件夹
  6. 上面的代码找到了新文件夹和图像(很好!)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Android MediaStore插入图像创建的附加文件

Android MediaStore插入图像创建的附加文件

我使用以下代码片段在MediaStore缓存中插入一个Image:

MediaStore.Images.Media.insertimage(getContentResolver(),selectedFile.getParent()file.separator selectedFile.getName(),selectedFile.getName(),null);

插入没问题,但它也在同一路径上创建了另一个图像缩略图.这在图库中不可见,但在使用文件浏览器浏览时,此图像缩略图可见.如何在此处停止创建此图像缩略图,以免混淆用户.

解决方法:

MediaStore.Images.Media.insertimage()的文档说它:

Insert an image and create a thumbnail
for it.

您实际需要做的是访问Media Scanner服务.
默认情况下,该服务在启动期间或插入SD卡后运行.你可以强制它使用意图运行,但你最终重新扫描整个SD卡一个.

当然,有一个更好的解决方案:

如果您正在开发API级别8或更高级别(Android 2.2),请使用
来自MediaScannerConnection的scanFile静态函数,记录为here.

对于API 7或更低版​​本,它有点复杂,但您可以使用以下帖子中最佳解释的包装器将所有内容放在一起:
dynamically add pictures to gallery widget

关于重命名由android 10中的应用程序创建的Mediastore的文件。正在使用Android API 30,但在API 29中显示错误的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Android API 30 中的外部文件读取和写入,在 JAVA 中使用 MediaStore API、Android CRUD MediaStore API 26+、Android Media Store API 在外部存储中找不到由 Google Photo 创建的图像、Android MediaStore插入图像创建的附加文件的相关信息,请在本站寻找。

本文标签: