【问题标题】:Android: Accessing File from Internal Storage Using RandomAccessFileAndroid:使用 RandomAccessFile 从内部存储访问文件
【发布时间】:2013-01-25 22:46:15
【问题描述】:

我正在创建一个需要从文件中读取数据的应用。我最初使用BufferedReaderInputStreamReader 从资产文件夹中读取它,但我遇到了内存问题(请参阅Android: File Reading - OutOfMemory Issue)。一个建议是将数据从资产文件夹复制到内部存储(不是 SD 卡),然后通过 RandomAccessFile 访问它。因此,我查找了如何将文件从资产复制到内部存储,并找到了 2 个来源:

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/RpXiMYV48Ww

http://developergoodies.blogspot.com/2012/11/copy-android-asset-to-internal-storage.html

我决定使用第二个中的代码并为我的文件修改它。所以它看起来像这样:

public void copyFile() {
    //Open your file in assets
    Context context = getApplicationContext();
    String destinationFile = context.getFilesDir().getPath() + File.separator + "text.txt";

    if (!new File(destinationFile).exists()) {
        try {
            copyFromAssetsToStorage(context, "text.txt", destinationFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }   
}

private void copyStream(InputStream input, OutputStream output) throws IOException {
    byte[] buffer = new byte[1024];
    int length = Input.read(buffer);
    while (length > 0) {
        output.write(buffer, 0, length);
        length = input.read(buffer);
    }
}

private void copyFromAssetsToStorage(Context context, String sourceFile, String destinationFile) throws IOException {
    InputStream inputStream = context.getAssets().open(sourceFile);
    OutputStream outputStream = new FileOutputStream(destinationFile);
    copyStream(inputStream , outputStream );
    outputStream.flush();
    outputStream.close();
    inputStream.close();
}

我假设这会将文件复制到应用程序的数据目录中。我无法对其进行测试,因为我希望能够使用RandomAccessFile 访问该文件。但是,我从来没有做过这两个中的任何一个(从资产和RandomAccessFile 复制文件),所以我被卡住了。这个应用程序的工作已经停止,因为这是唯一阻止我完成它的事情。

任何人都可以向我提供有关如何使用RandomAccessFile 访问数据的更正、建议和正确实现吗? (数据是每行长度为 4-15 个字符的字符串列表。)

编辑*

private File createCacheFile(Context context, String filename){
File cacheFile = new File(context.getCacheDir(), filename);

    if (cacheFile.exists()) {
        return cacheFile ;
    }

    InputStream inputStream = null;
    FileOutputStream fileOutputStream = null;

    try {

        inputStream = context.getAssets().open(filename);
        fileOutputStream = new FileOutputStream(cacheFile);

        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        int length = -1;
        while ( (length = inputStream.read(buffer)) > 0) {
            fileOutputStream.write(buffer,0,length);
        }

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    finally {
        try {
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return cacheFile;
}

【问题讨论】:

    标签: android file-io android-assets randomaccessfile


    【解决方案1】:

    1- 将文件从资产复制到缓存目录

    此代码仅用于说明,您必须进行适当的异常处理关闭资源

    private File createCacheFile(Context context, String filename){
      File cacheFile = new File(context.getCacheDir(), filename);
    
      if (cacheFile.exists()) {
          return cacheFile ;
      }
    
    
      InputStream inputStream = context.getAssets().open(filename);
      FileOutputStream fileOutputStream = new FileOutputStream(cacheFile);
    
      int bufferSize = 1024;
      byte[] buffer = new byte[bufferSize];
      int length = -1;
      while ( (length = inputStream.read(buffer)) > 0) {
         fileOutputStream.write(buffer,0,length);
      }
    
      fileOutputStream.close();
      inputStream.close();
    
      return cacheFile;
    }
    

    2- 使用RandomAccessFile打开文件

    File cacheFile = createCacheFile(context, "text.txt");
    RandomAccessFile randomAccessFile = new RandomAccessFile(cacheFile, "r");
    
    // Process the file
    
    randomAccessFile.close();    
    

    附带说明,您应该遵循 Java 命名约定,例如您的方法和变量名称应以小写字母开头,例如 copyFromAssetsToStoragedestinationFile

    编辑:

    您应该为每个close() 操作创建一个单独的try/catch,因此如果一个失败,另一个仍然会被执行并检查它们是否不是null

    finally {
        try {
           if(fileOutputStream!=null){
              fileOutputStream.close();            
           }
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        try {
          if(inputStream!=null){
           inputStream.close();      
          }      
        } catch (IOException e) {
            e.printStackTrace();
        }
    }  
    

    【讨论】:

    • 感谢您的回复。我想确保我做对了。我是否正确实施了 try/catch(见编辑)?没有错误,但这并不一定意味着它是正确的。另外,我是否必须进行任何类型的“清理”,例如每次使用后清除缓存?
    • 您应该在try/catch 块之外定义fileOutputStreaminputStream,并在检查它们不为空后在final 块中关闭它们(您需要为每个try/catch close()操作)
    • 哇...呃...好吧。我假设这也应该在不同的线程上?目前我已经设置了一个异步线程,那么我是否只需在异步类的 doInBackground 方法中添加第 2 步代码?
    • 另外,当我尝试在 fileOutputStream/inputStream 之后放置 try 时它会抱怨...说它应该被 try/catch 包围。
    • 我为所有的问题道歉。我只是想了解一些事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    相关资源
    最近更新 更多