【问题标题】:Android: How to detect a directory in the assets folder?Android:如何检测资产文件夹中的目录?
【发布时间】:2011-09-10 16:06:49
【问题描述】:

我正在检索这样的文件

String[] files = assetFiles.list("EngagiaDroid"); 

我们如何知道它是文件还是目录?

我想遍历 assets 文件夹中的目录,然后复制其所有内容。

【问题讨论】:

    标签: java android file exists


    【解决方案1】:

    您可以使用http://developer.android.com/reference/java/io/File.html#isDirectory() 检查文件是否代表目录。是这个意思吗?

    【讨论】:

    • 感谢您的回复。是的,但是当我尝试它时,当文件在您的资产文件夹中时它不起作用。可能是因为文件包含在包中。
    • 我最终使用this code。我执行此代码乘以我的文件夹数。 :)
    • AssetManager 不返回 File 对象,因此 File API 不适用。
    【解决方案2】:

    你可以从Android File开始

    【讨论】:

    • 感谢您的回复。但我不认为像 isDirectory 这样的一些功能在资产文件夹中不起作用
    【解决方案3】:

    我认为更通用的解决方案(如果您有子文件夹等)将是这样的(基于您链接到的解决方案,我也已将其添加到那里):

    ...

    copyFileOrDir("myrootdir");
    

    ...

    private void copyFileOrDir(String path) {
        AssetManager assetManager = this.getAssets();
        String assets[] = null;
        try {
            assets = assetManager.list(path);
            if (assets.length == 0) {
                copyFile(path);
            } else {
                String fullPath = "/data/data/" + this.getPackageName() + "/" + path;
                File dir = new File(fullPath);
                if (!dir.exists())
                    dir.mkdir();
                for (int i = 0; i < assets.length; ++i) {
                    copyFileOrDir(path + "/" + assets[i]);
                }
            }
        } catch (IOException ex) {
            Log.e("tag", "I/O Exception", ex);
        }
    }
    
    private void copyFile(String filename) {
        AssetManager assetManager = this.getAssets();
    
        InputStream in = null;
        OutputStream out = null;
        try {
            in = assetManager.open(filename);
            String newFileName = "/data/data/" + this.getPackageName() + "/" + filename;
            out = new FileOutputStream(newFileName);
    
            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
            in = null;
            out.flush();
            out.close();
            out = null;
        } catch (Exception e) {
            Log.e("tag", e.getMessage());
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      我发现了这个变种:

      try {
          AssetFileDescriptor desc = getAssets().openFd(path);  // Always throws exception: for directories and for files
          desc.close();  // Never executes
      } catch (Exception e) {
          exception_message = e.toString();
      }
      
      if (exception_message.endsWith(path)) {  // Exception for directory and for file has different message
          // Directory
      } else {
          // File
      }
      

      它比 .list() 更快

      【讨论】:

      • 这不会为未压缩的文件抛出,所以它不会总是抛出。但这很容易解决。另一方面,依赖异常消息对我来说并不好。他们可能会改变。
      【解决方案5】:

      另一种依赖异常的方式:

      private void checkAssets(String path, AssetManager assetManager) {
          String TAG = "CheckAssets";
          String[] fileList;
          String text = "";
          if (assetManager != null) {
              try {
                  fileList = assetManager.list(path);
              } catch (IOException e) {
                  Log.e(TAG, "Invalid directory path " + path);
                  return;
              }
          } else {
              fileList = new File(path).list();
          }
      
          if (fileList != null && fileList.length > 0) {
              for (String pathInFolder : fileList) {
                  File absolutePath = new File(path, pathInFolder);
      
                  boolean isDirectory = true;
                  try {
                      if (assetManager.open(absolutePath.getPath()) != null) {
                          isDirectory = false;
                      }
                  } catch (IOException ioe) {
                      isDirectory = true;
                  }
      
                  text = absolutePath.getAbsolutePath() + (isDirectory ? " is Dir" : " is File");
                  Log.d(TAG, text);
                  if (isDirectory) {
                      checkAssets(absolutePath.getPath(), assetManager);
                  }
              }
          } else {
              Log.e(TAG, "Invalid directory path " + path);
          }
      }
      

      然后只需调用 checkAssets("someFolder", getAssets());checkAssets("", getAssets()); 如果您想检查根资产文件夹。但请注意,根资产文件夹还包含其他目录/文件(例如 webkit、图像等)

      【讨论】:

        【解决方案6】:

        您可以使用 AssetManager 的列表方法。 资产中的任何目录至少应该有一个文件,构建应用程序时将忽略空目录。 因此,要确定某个路径是否是目录,请像这样使用:

        AssetManager manager = activity.getAssets();
        try {
            String[] files = manager.list(path);
            if (files.length > 0) {
                //directory
            } else {
                //file
            }
        } catch (Exception e) {
            //not exists.
        }
        

        【讨论】:

          【解决方案7】:

          在您的特定情况下,由于您通过list 检索文件,因此您已经知道这些名称存在。这大大简化了问题。你可以简单地使用这个:

          public static boolean isAssetAFolder(AssetManager assetManager, String assetPath) throws IOException {
          
              // Attempt opening as a file,
              try {
                  InputStream inputStream = assetManager.open(assetPath); inputStream.close();
                  return false; // A file indeed.
              } catch (FileNotFoundException e) {
                  // We already know this name exists. This is a folder.
                  return true;
              }
          }
          

          另一方面,如果您需要一个通用的解决方案来检测某个路径是否既存在又是一个文件夹,您可以使用这个:

          public static boolean isAssetAFolder(AssetManager assetManager, String assetPath) throws IOException {
          
              // Attempt opening as a file,
              try {
                  InputStream inputStream = assetManager.open(assetPath); inputStream.close();
                  return false; // A file indeed.
              } catch (FileNotFoundException e) {
                  // This could be a folder, or this path doesn't exist at all. Further checking needed,
                  return assetPathExists(assetManager, assetPath);
              }
          }
          
          // If you are checking a file name "icon.png" inside your assets folder, the assetPath should be "icon.png".
          public static boolean assetPathExists(AssetManager assetManager, String assetPath) throws IOException {
          
              // Assume that "" exists by default,
              if (assetPath.isEmpty()) return true;
          
              // Reject paths that point outside the assets folder,
              if (assetPath.startsWith("..") || assetPath.startsWith("/")) return false;
          
              // For other file/folder paths, we'll search the parent folder,
              File fileOrFolder = new File(assetPath);
              String parent = ((parent=fileOrFolder.getParent()) != null) ? parent : ""; // Handle null parents.
              if (!Arrays.asList(assetManager.list(parent)).contains(fileOrFolder.getName())) return false;
          
              // Getting this far means that the specified assetPath indeed exists. However, we didn't handle files
              // with trailing "/". For instance, "icon.png/" shouldn't be considered existing although "icon.png"
              // does.
          
              // If the path doesn't end with a "/", we are safe,
              if (!assetPath.endsWith("/")) return true;
          
              // Remove the trailing slash,
              assetPath = assetPath.substring(0, assetPath.length()-1);
          
              // Attempt opening as a file,
              try {
                  InputStream inputStream = assetManager.open(assetPath); inputStream.close();
                  return false; // It's indeed a file (like "icon.png"). "icon.png/" shouldn't exist.
              } catch (FileNotFoundException e) {
                  return true; // This is a folder that exists.
              }
          }
          

          我为 Web 服务器编写了这些,因此我无法对输入路径的形状做出假设。但是,如果您设置了一些规则,则可以稍微简化一下。一旦确定资产的类型,此代码会立即返回,以避免额外的处理开销。

          【讨论】:

            【解决方案8】:

            令人震惊的事实是,尽管在近 10 年前被问到,没有简单、优雅、广受赞誉的方法来确定 AssetManager.list() 返回的数组中的元素是文件还是迄今为止,任何答案都提供了一个目录。

            因此,例如,如果资产目录包含一千个元素,那么似乎需要一千个 I/O 操作来隔离目录。

            对于任何元素,也不存在任何用于获取其父目录的本机方法 - 对于像资产 Browser / Picker 这样复杂的东西至关重要 - 您最终可能会看到一些非常丑陋的代码。

            boolean isAssetDirectory = !elementName.contains(".");
            

            对我有用的横向方法是假设名称中没有点 (.) 的任何元素都是目录。如果这个假设后来被证明是错误的,它可以很容易地纠正。

            资产文件通常存在,因为将它们放在那里。部署区分目录和文件的命名约定。

            【讨论】:

              【解决方案9】:

              你也可以试试这个,它对我有用,因为你不能只依赖 .list()

              public static boolean isDirectory(Context context, String path) throws IOException {
                  //If list returns any entries, than the path is a directory
                  String[] files = context.getAssets().list(path);
                  if (files != null && files.length > 0) {
                      return true;
                  } else {
                      try {
                          //If we can open a stream then the path leads to a file
                          context.getAssets().open(path);
                          return false;
                      } catch (Exception ex) {
                          //.open() throws exception if it's a directory that you're passing as a parameter
                          return true;
                      }
                  }
              }
              

              【讨论】:

              • 虽然这是正确的,但如果你可以用 Java 重写它会更好,所以这是一个更有用的答案
              • 完成,我将代码转换为 Java,希望答案现在可以帮助更多人。
              猜你喜欢
              • 1970-01-01
              • 2019-02-22
              • 1970-01-01
              • 1970-01-01
              • 2013-10-14
              • 2014-09-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多