【问题标题】:How to programmatically move, copy and delete files and directories on SD?如何以编程方式移动、复制和删除 SD 上的文件和目录?
【发布时间】:2011-05-09 20:31:05
【问题描述】:

我想以编程方式移动、复制和删除 SD 卡上的文件和目录。我已经进行了 Google 搜索,但找不到任何有用的信息。

【问题讨论】:

    标签: android file directory copy move


    【解决方案1】:

    Use standard Java I/O。使用 Environment.getExternalStorageDirectory() 获取外部存储的根目录(在某些设备上,它是 SD 卡)。

    【讨论】:

    • 这些复制文件的内容,但并没有真正复制文件 - 即未复制文件系统元数据...我想要一种方法来执行此操作(如 shell cp)进行备份在我覆盖文件之前。有可能吗?
    • 不幸的是,标准 Java I/O 中最相关的部分 java.nio.file 在 Android(API 级别 21)上不可用。
    • @CommonsWare:我们可以务实地访问 SD 中的私人文件吗?或删除任何私人文件?
    • 随着 android 10 范围存储的发布成为新规范,所有对文件进行操作的方法也发生了变化,除非您添加“RequestLagacyStorage”,否则 java.io 的操作方式将不再有效您的 Manifest 方法 Environment.getExternalStorageDirectory() 中的值“true”也被贬低了
    • 这个答案在 2021 年不再可用。
    【解决方案2】:

    在清单中设置正确的权限

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

    下面是一个以编程方式移动文件的函数

    private void moveFile(String inputPath, String inputFile, String outputPath) {
    
        InputStream in = null;
        OutputStream out = null;
        try {
    
            //create output directory if it doesn't exist
            File dir = new File (outputPath); 
            if (!dir.exists())
            {
                dir.mkdirs();
            }
    
    
            in = new FileInputStream(inputPath + inputFile);        
            out = new FileOutputStream(outputPath + inputFile);
    
            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
            in = null;
    
                // write the output file
                out.flush();
            out.close();
            out = null;
    
            // delete the original file
            new File(inputPath + inputFile).delete();  
    
    
        } 
    
             catch (FileNotFoundException fnfe1) {
            Log.e("tag", fnfe1.getMessage());
        }
              catch (Exception e) {
            Log.e("tag", e.getMessage());
        }
    
    }
    

    删除文件使用

    private void deleteFile(String inputPath, String inputFile) {
        try {
            // delete the original file
            new File(inputPath + inputFile).delete();  
        }
        catch (Exception e) {
            Log.e("tag", e.getMessage());
        }
    }
    

    复制

    private void copyFile(String inputPath, String inputFile, String outputPath) {
    
        InputStream in = null;
        OutputStream out = null;
        try {
    
            //create output directory if it doesn't exist
            File dir = new File (outputPath); 
            if (!dir.exists())
            {
                dir.mkdirs();
            }
    
    
            in = new FileInputStream(inputPath + inputFile);        
            out = new FileOutputStream(outputPath + inputFile);
    
            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
            in = null;
    
                // write the output file (You have now copied the file)
                out.flush();
            out.close();
            out = null;        
    
        }  catch (FileNotFoundException fnfe1) {
            Log.e("tag", fnfe1.getMessage());
        }
                catch (Exception e) {
            Log.e("tag", e.getMessage());
        }
    
    }
    

    【讨论】:

    • 不要忘记在清单中设置权限
    • 另外,不要忘记在 inputPath 和 outputPath 的末尾添加一个斜杠,例如:/sdcard/ NOT /sdcard
    • 我试图移动但我不能。这是我的代码 moveFile(file.getAbsolutePath(),myfile, Environment.getExternalStorageDirectory()+ "/CopyEcoTab/" );
    • 另外,不要忘记通过 AsyncTask 或 Handler 等在后台线程上执行这些操作。
    • @DanielLeahy 如何确保文件已经复制成功,然后只删除原始文件?
    【解决方案3】:

    删除

    public static void deleteRecursive(File fileOrDirectory) {
    
     if (fileOrDirectory.isDirectory())
        for (File child : fileOrDirectory.listFiles())
            deleteRecursive(child);
    
        fileOrDirectory.delete();
    
        }
    

    查看this链接了解上述功能。

    复制

    public static void copyDirectoryOneLocationToAnotherLocation(File sourceLocation, File targetLocation)
        throws IOException {
    
    if (sourceLocation.isDirectory()) {
        if (!targetLocation.exists()) {
            targetLocation.mkdir();
        }
    
        String[] children = sourceLocation.list();
        for (int i = 0; i < sourceLocation.listFiles().length; i++) {
    
            copyDirectoryOneLocationToAnotherLocation(new File(sourceLocation, children[i]),
                    new File(targetLocation, children[i]));
        }
    } else {
    
        InputStream in = new FileInputStream(sourceLocation);
    
        OutputStream out = new FileOutputStream(targetLocation);
    
        // Copy the bits from instream to outstream
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }
    
    }
    

    移动

    移动只是将文件夹复制到另一个位置然后删除文件夹就是这样

    清单

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

    【讨论】:

    • 这就像一个魅力。在 API 25 到 29 中尝试过。用于将我的文件从顶级存储迁移到应用目录以实现范围存储。
    【解决方案4】:

    移动文件:

    File from = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/kaic1/imagem.jpg");
    File to = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/kaic2/imagem.jpg");
    from.renameTo(to);
    

    【讨论】:

    • 抬头; “两条路径都在同一个挂载点上。在 Android 上,应用程序在尝试在内部存储和 SD 卡之间进行复制时最有可能遇到此限制。”
    • renameTo 失败,没有任何解释
    • 奇怪的是,这会创建一个具有所需名称的目录,而不是一个文件。有什么想法吗?文件“来自”是可读的,它们都在 SD 卡中。
    【解决方案5】:
    File from = new File(Environment.getExternalStorageDirectory().getAbsolutePath().getAbsolutePath()+"/kaic1/imagem.jpg");
    File to = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/kaic2/imagem.jpg");
    from.renameTo(to);
    

    【讨论】:

    • File.renameTo 仅适用于同一文件系统卷。您还应该检查 renameTo 的结果。
    【解决方案6】:

    如果你使用 Guava,可以使用Files.move(from, to)

    【讨论】:

    • 链接已损坏。
    • @LarsH 我修复了 Guava JavaDoc 的链接。
    【解决方案7】:

    移动文件功能:

    private void moveFile(File file, File dir) throws IOException {
        File newFile = new File(dir, file.getName());
        FileChannel outputChannel = null;
        FileChannel inputChannel = null;
        try {
            outputChannel = new FileOutputStream(newFile).getChannel();
            inputChannel = new FileInputStream(file).getChannel();
            inputChannel.transferTo(0, inputChannel.size(), outputChannel);
            inputChannel.close();
            file.delete();
        } finally {
            if (inputChannel != null) inputChannel.close();
            if (outputChannel != null) outputChannel.close();
        }
    
    }
    

    【讨论】:

    • 复制文件需要做哪些修改?
    • @BlueMango 删除第 10 行 file.delete()
    • 此代码不适用于 1 gb 或 2 gb 等大文件。
    • @Vishal 为什么不呢?
    • 我猜@Vishal 意味着复制和删除一个大文件比移动该文件需要更多的磁盘空间和时间。
    【解决方案8】:
    /**
         * Copy the local DB file of an application to the root of external storage directory
         * @param context the Context of application
         * @param dbName The name of the DB
         */
        private void copyDbToExternalStorage(Context context , String dbName){
    
            try {
                File name = context.getDatabasePath(dbName);
                File sdcardFile = new File(Environment.getExternalStorageDirectory() , "test.db");//The name of output file
                sdcardFile.createNewFile();
                InputStream inputStream = null;
                OutputStream outputStream = null;
                inputStream = new FileInputStream(name);
                outputStream = new FileOutputStream(sdcardFile);
                byte[] buffer = new byte[1024];
                int read;
                while ((read = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, read);
                }
                inputStream.close();
                outputStream.flush();
                outputStream.close();
            }
            catch (Exception e) {
                Log.e("Exception" , e.toString());
            }
        }
    

    【讨论】:

      【解决方案9】:
      1. 权限:

        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        
      2. 获取SD卡根文件夹:

        Environment.getExternalStorageDirectory()
        
      3. 删除文件:这是一个关于如何删除根文件夹中所有空文件夹的示例:

        public static void deleteEmptyFolder(File rootFolder){
            if (!rootFolder.isDirectory()) return;
        
            File[] childFiles = rootFolder.listFiles();
            if (childFiles==null) return;
            if (childFiles.length == 0){
                rootFolder.delete();
            } else {
                for (File childFile : childFiles){
                    deleteEmptyFolder(childFile);
                }
            }
        }
        
      4. 复制文件:

        public static void copyFile(File src, File dst) throws IOException {
            FileInputStream var2 = new FileInputStream(src);
            FileOutputStream var3 = new FileOutputStream(dst);
            byte[] var4 = new byte[1024];
        
            int var5;
            while((var5 = var2.read(var4)) > 0) {
                var3.write(var4, 0, var5);
            }
        
            var2.close();
            var3.close();
        }
        
      5. 移动文件 = 复制 + 删除源文件

      【讨论】:

        【解决方案10】:

        使用 Square 的 Okio 复制文件:

        BufferedSink bufferedSink = Okio.buffer(Okio.sink(destinationFile));
        bufferedSink.writeAll(Okio.source(sourceFile));
        bufferedSink.close();
        

        【讨论】:

          【解决方案11】:

          Xamarin Android

          public static bool MoveFile(string CurrentFilePath, string NewFilePath)
          {
              try
              {
                  using (var f = new File(CurrentFilePath))
                  using (var i = new FileInputStream(f))
                  using (var o = new FileOutputStream(NewFilePath))
                  {
                      i.Channel.TransferTo(0, i.Channel.Size(), o.Channel);
                      f.Delete();
                  }
          
                  return true;
              }
              catch { return false; }
          }
          
          public static bool CopyFile(string CurrentFilePath, string NewFilePath)
          {
              try
              {
                  using (var i = new FileInputStream(CurrentFilePath))
                  using (var o = new FileOutputStream(NewFilePath))
                      i.Channel.TransferTo(0, i.Channel.Size(), o.Channel);
          
                  return true;
              }
              catch { return false; }
          }
          
          public static bool DeleteFile(string FilePath)
          {
              try
              {
                  using (var file = new File(FilePath))
                      file.Delete();
          
                  return true;
              }
              catch { return false; }
          }
          

          【讨论】:

            【解决方案12】:

            要移动文件,可以使用此 api,但您需要 atleat 26 作为 api 级别 -

            move file

            但是如果你想移动目录,没有支持,所以可以使用这个本机代码

                import org.apache.commons.io.FileUtils;
            
                import java.io.IOException;
                import java.io.File;
            
                public class FileModule {
            
                public void moveDirectory(String src, String des) {
                File srcDir = new File(src);
                File destDir = new File(des);
                 try {
                    FileUtils.moveDirectory(srcDir,destDir);
                } catch (Exception e) {
                  Log.e("Exception" , e.toString());
                  }
                }
            
                public void deleteDirectory(String dir) {
                  File delDir = new File(dir);
                  try {
                    FileUtils.deleteDirectory(delDir);
                   } catch (IOException e) {
                  Log.e("Exception" , e.toString());
                  }
                 }
                }
            

            【讨论】:

              【解决方案13】:

              使用 kotlin 移动文件。应用必须有权在目标目录中写入文件。

              @Throws(FileNotFoundException::class, IOError::class)
              private fun moveTo(source: File, dest: File, destDirectory: File? = null) {
              
                  if (destDirectory?.exists() == false) {
                      destDirectory.mkdir()
                  }
              
                  val fis = FileInputStream(source)
                  val bufferLength = 1024
                  val buffer = ByteArray(bufferLength)
                  val fos = FileOutputStream(dest)
                  val bos = BufferedOutputStream(fos, bufferLength)
                  var read = fis.read(buffer, 0, read)
                  while (read != -1) {
                      bos.write(buffer, 0, read)
                      read = fis.read(buffer) // if read value is -1, it escapes loop.
                  }
                  fis.close()
                  bos.flush()
                  bos.close()
              
                  if (!source.delete()) {
                      HLog.w(TAG, klass, "failed to delete ${source.name}")
                  }
              }
              

              【讨论】:

                【解决方案14】:

                移动文件或文件夹:

                public static void moveFile(File srcFileOrDirectory, File desFileOrDirectory) throws IOException {
                    File newFile = new File(desFileOrDirectory, srcFileOrDirectory.getName());
                    try (FileChannel outputChannel = new FileOutputStream(newFile).getChannel(); FileChannel inputChannel = new FileInputStream(srcFileOrDirectory).getChannel()) {
                        inputChannel.transferTo(0, inputChannel.size(), outputChannel);
                        inputChannel.close();
                        deleteRecursive(srcFileOrDirectory);
                    }
                }
                
                private static void deleteRecursive(File fileOrDirectory) {
                    if (fileOrDirectory.isDirectory())
                        for (File child : Objects.requireNonNull(fileOrDirectory.listFiles()))
                            deleteRecursive(child);
                    fileOrDirectory.delete();
                }
                

                【讨论】:

                  【解决方案15】:

                  在 Kotlin 中你可以使用 copyTo() 扩展函数,

                  sourceFile.copyTo(destFile, true)
                  

                  【讨论】:

                    猜你喜欢
                    • 2011-06-05
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-03-12
                    • 2014-08-30
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多