24

如何从现有的 URI 中保存媒体文件(例如 .mp3),我从隐式意图中获取该文件?

4

9 回答 9

35

用这个方法,有效

void savefile(URI sourceuri)
{
    String sourceFilename= sourceuri.getPath();
    String destinationFilename = android.os.Environment.getExternalStorageDirectory().getPath()+File.separatorChar+"abc.mp3";

    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;

    try {
      bis = new BufferedInputStream(new FileInputStream(sourceFilename));
      bos = new BufferedOutputStream(new FileOutputStream(destinationFilename, false));
      byte[] buf = new byte[1024];
      bis.read(buf);
      do {
        bos.write(buf);
      } while(bis.read(buf) != -1);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (bis != null) bis.close();
        if (bos != null) bos.close();
      } catch (IOException e) {
            e.printStackTrace();
      }
    }
}
于 2012-10-30T06:46:32.700 回答
11
private static String FILE_NAM  = "video";
String outputfile = getFilesDir() + File.separator+FILE_NAM+"_tmp.mp4";

InputStream in = getContentResolver().openInputStream(videoFileUri);
private static File createFileFromInputStream(InputStream inputStream, String fileName) {

    try {
        File f = new File(fileName);
        f.setWritable(true, false);
        OutputStream outputStream = new FileOutputStream(f);
        byte buffer[] = new byte[1024];
        int length = 0;

        while((length=inputStream.read(buffer)) > 0) {
            outputStream.write(buffer,0,length);
        }

        outputStream.close();
        inputStream.close();

        return f;
    } catch (IOException e) {
        System.out.println("error in creating a file");
        e.printStackTrace();
    }

    return null;
}
于 2013-10-24T04:38:42.613 回答
10

如果 Uri 是从 Google Drive 接收的,它也可以是虚拟文件 Uri。查看CommonsWare 的这篇文章以获取更多信息。因此,在从 Uri 保存文件时,您也必须考虑这种情况。

要查找文件 Uri 是否是虚拟的,您可以使用

private static boolean isVirtualFile(Context context, Uri uri) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        if (!DocumentsContract.isDocumentUri(context, uri)) {
            return false;
        }
        Cursor cursor = context.getContentResolver().query(
                uri,
                new String[]{DocumentsContract.Document.COLUMN_FLAGS},
                null, null, null);
        int flags = 0;
        if (cursor.moveToFirst()) {
            flags = cursor.getInt(0);
        }
        cursor.close();
        return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
    } else {
        return false;
    }
}

您可以像这样从此虚拟文件中获取流数据:

private static InputStream getInputStreamForVirtualFile(Context context, Uri uri, String mimeTypeFilter)
        throws IOException {

    ContentResolver resolver = context.getContentResolver();
    String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);
    if (openableMimeTypes == null || openableMimeTypes.length < 1) {
        throw new FileNotFoundException();
    }
    return resolver
            .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
            .createInputStream();
}

要查找 MIME 类型,请尝试

private static String getMimeType(String url) {
    String type = null;
    String extension = MimeTypeMap.getFileExtensionFromUrl(url);
    if (extension != null) {
        type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
    return type;
}

总的来说,您可以使用

public static boolean saveFile(Context context, String name, Uri sourceuri, String destinationDir, String destFileName) {

    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    InputStream input = null;
    boolean hasError = false;

    try {
        if (isVirtualFile(context, sourceuri)) {
            input = getInputStreamForVirtualFile(context, sourceuri, getMimeType(name));
        } else {
            input = context.getContentResolver().openInputStream(sourceuri);
        }

        boolean directorySetupResult;
        File destDir = new File(destinationDir);
        if (!destDir.exists()) {
            directorySetupResult = destDir.mkdirs();
        } else if (!destDir.isDirectory()) {
            directorySetupResult = replaceFileWithDir(destinationDir);
        } else {
            directorySetupResult = true;
        }

        if (!directorySetupResult) {
            hasError = true;
        } else {
            String destination = destinationDir + File.separator + destFileName;
            int originalsize = input.available();

            bis = new BufferedInputStream(input);
            bos = new BufferedOutputStream(new FileOutputStream(destination));
            byte[] buf = new byte[originalsize];
            bis.read(buf);
            do {
                bos.write(buf);
            } while (bis.read(buf) != -1);
        }
    } catch (Exception e) {
        e.printStackTrace();
        hasError = true;
    } finally {
        try {
            if (bos != null) {
                bos.flush();
                bos.close();
            }
        } catch (Exception ignored) {
        }
    }

    return !hasError;
}

private static boolean replaceFileWithDir(String path) {
    File file = new File(path);
    if (!file.exists()) {
        if (file.mkdirs()) {
            return true;
        }
    } else if (file.delete()) {
        File folder = new File(path);
        if (folder.mkdirs()) {
            return true;
        }
    }
    return false;
}

从 AsycTask 调用此方法。让我知道这是否有帮助。

于 2017-12-06T06:22:08.957 回答
5

我已使用以下代码将文件从从 Intent 返回的现有 Uri 保存到我的应用托管的 Uri:

 private void copyFile(Uri pathFrom, Uri pathTo) throws IOException {
        try (InputStream in = getContentResolver().openInputStream(pathFrom)) {
            if(in == null) return;
            try (OutputStream out = getContentResolver().openOutputStream(pathTo)) {
                if(out == null) return;
                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
            }
        }
    }
于 2019-12-18T15:26:38.457 回答
3

这是最简单和最干净的:

private void saveFile(Uri sourceUri, File destination)
    try {
        File source = new File(sourceUri.getPath());
        FileChannel src = new FileInputStream(source).getChannel();
        FileChannel dst = new FileOutputStream(destination).getChannel();
        dst.transferFrom(src, 0, src.size());
        src.close();
        dst.close();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
于 2014-07-18T14:40:39.063 回答
3

android.net.Uri从外部源接收 a时,保存文件的最佳方法是从流中:

try (InputStream ins = activity.getContentResolver().openInputStream(source_uri)) {
    File dest = new File(destination_path);
    createFileFromStream(ins, dest);
} catch (Exception ex) {
    Log.e("Save File", ex.getMessage());
    ex.printStackTrace();
}

createFileFromStream方法:

public static void createFileFromStream(InputStream ins, File destination) {
    try (OutputStream os = new FileOutputStream(destination)) {
        byte[] buffer = new byte[4096];
        int length;
        while ((length = ins.read(buffer)) > 0) {
            os.write(buffer, 0, length);
        }
        os.flush();
    } catch (Exception ex) {
        Log.e("Save File", ex.getMessage());
        ex.printStackTrace();
    }
}
于 2019-08-07T09:35:46.420 回答
2

1.从 URI 路径创建一个文件:

File from = new File(uri.toString());

2.在您希望文件另存为的位置创建另一个文件:

File to = new File("target file path");

3.将文件重命名为:

from.renameTo(to);

这样,默认路径中的文件将自动删除并在新路径中创建。

于 2012-10-30T06:18:06.320 回答
0

如何获取外部存储位置并保存文件

这个答案不是针对问题,而是针对标题。由于没有文章完全解释该过程,因此花了几个小时才弄清楚如何做到这一点,而其中一些已经存在多年并且使用了已弃用的 API。希望这可能对未来的开发人员有所帮助。

获取外部存储的位置

例如,从片段内部,

// when user choose file location
private val uriResult = registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
    // do when user choose file location
    createFile(uri)
}

fun openFileChooser() {
    // startActivityForResult() is deprecated
    val suggestedFileName = "New Document.txt"
    uriResult.launch(suggestedFileName)
}

使用 Uri 写入文件数据

java.io.File从 an创建 a 似乎很困难android.net.Uri,因为没有直接的方法将 an 转换android.net.Urijava.net.URI。但如果你有ApplicationContext你可以很容易地做到这一点。

fun createFile(uri: Uri) {
    try {
requireContext().applicationContext.contentResolver.openFileDescriptor(uri, "w")?.use { fd ->
        FileOutputStream(fd).use { fos ->

            // do your job on the FileOutputStream
            // also use background thread

            fos.close()
        }
    }
  } catch (e: Exception) {

  }
}

注意文件操作会抛出多个异常,请谨慎处理。并且还在工作线程中进行文件操作。

于 2022-03-03T18:33:50.463 回答
-2

您可以使用

new File(uri.getPath());
于 2019-12-11T12:14:52.317 回答