【问题标题】:BufferedInputStream or FileInputStream IOExceptionBufferedInputStream 或 FileInputStream IOException
【发布时间】:2016-02-07 19:17:53
【问题描述】:

我刚刚发布了一个解析本地文件并对数据进行处理的 Android 应用。 几天前,我的一位客户向我报告了一个错误,每次他尝试处理他的文件时,应用程序都会崩溃。

这是他发给我的错误日志:

java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:300)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: lock == null
    at java.io.Reader.<init>(Reader.java:64)
    at java.io.InputStreamReader.<init>(InputStreamReader.java:120)

与此相关的代码是这样的:

// EDIT 1: Following greenapps comment I will put a more realistic version of this 
// method (The first version was invented because I wanted to be breaf)
public void selectFile()
{
    List<File> files = getDocsToParse();
    this.listview.setAdapter(this.myadapter);
    this.listview.setOnItemClickListener(new OnItemClickListener()
    {
        ...
        @Override
        public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
        parseFile(files.get(position));
                }
        ...
    }
    this.myadapter.addFiles(files);
}

public static List<File> getDocsToParse() {
    File sdcard = Environment.getExternalStorageDirectory();
    File subdir = new File(sdcard, "MyAppFolder/Files/");
    // EDIT 2: I'm using  subdir.mkdirs(); because I want to 
    // create MyAppFolder/Files/ folders the first time the user use the app. 
    // Is this not correct? Should I create these folders any other way? 
    if (!subdir.exists()) {
        subdir.mkdirs();
    }
    File files[] = subdir.listFiles();
    List<File> filterFiles = new ArrayList<File>();
    for (int i = 0; i < files.length; i++) {
        File file = files[i];
        filterFiles.add(file);
    }
    return filterFiles;
}

public void parseFile(File fileToParse)
{
    long totalSize = 0;
    InputStream is = null;
    try {
            totalSize = fileToParse.length();
            is = new BufferedInputStream(new FileInputStream(fileToParse));
    } catch (IOException e) {
        e.printStackTrace();
    }
    BufferedReader reader = null;
    reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
    String line = "";
    StringTokenizer st = null;
    try {
        while ((line = reader.readLine()) != null) {
           // Here I parse the file
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

崩溃的行是这一行:

reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));

我知道这是因为“is”为空,我应该抓住这种情况以避免应用崩溃(我将在下一个版本中解决这个问题)。

编辑3:你是对的,greenapps,我会在使用它之前检查它是否为空,否则我不会使用它。

我知道“is”是空的,因为有一个 IOException 这样做:

 totalSize = fileToParse.length();
    is = new BufferedInputStream(new FileInputStream(fileToParse));

编辑 4:当然,如果这给了我一个 IOEXception,我将不得不更改我的代码以做出完全不同的事情。

我在网上找不到原因,所以这两行代码可能会抛出 IOException。

认为 fileToParse 没问题,或者至少不为空,因为我将此“文件”列表传递给适配器以使用 files.get(i).getName() 显示它们的文件名,并且名称显示正确.

我必须补充一点,要处理的文件非常大,并且包含敏感的个人数据,因此用户无法将其发送给我,因此我可以对其进行测试。

我的所有文件都没有给我这个错误,如果没有有问题的文件,我很难追踪问题,所以我不得不猜测。知道什么原因会导致此错误吗?

非常感谢和亲切的问候!

编辑 5:根据 ctarabusi 的建议,我将 parseFile 方法更改为:

public void parseFile(File fileToParse)
{
    long totalSize = 0;
    InputStream is = null;
    try {
            totalSize = fileToParse.length();
            is = new BufferedInputStream(new FileInputStream(fileToParse));
            BufferedReader reader = null;
            reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
            String line = "";
            StringTokenizer st = null;
            while ((line = reader.readLine()) != null) {
               // Here I parse the file
            }
    } catch (IOException e) {
          Toast.makeText(getApplicationContext(), "Error parsing file", Toast.LENGTH_LONG).show();
        e.printStackTrace();
    } finally {
        if(is != null)
        {
            try
            {
                is.close();
            }
            catch (IOException e)
            {
                Log.e("", e.getMessage(), e);
            }
        }
    }
}

我的测试再次正常工作,但用户告诉我他看到“解析文件错误”消息,所以它仍然失败。

我还能检查什么?

【问题讨论】:

  • 您是否在清单中指定了“READ_EXTERNAL_STORAGE”权限?如果您的客户使用 API 19+ 的电话并且您不使用“WRITE_EXTERNAL_STORAGE”,则需要此选项。此外,您可以尝试在赋值行设置断点并检查变量是否具有预期值。
  • 嗨!我的 Android 清单中有 WRITE_EXTERNAL_STORAGE 权限,所以我想这没问题。
  • '理解这是因为“is”为空,我应该抓住这种情况以避免应用程序崩溃'。不,您应该在使用它之前检查 is 是否为空。如果是,请不要使用它。
  • 'if (!subdir.exists()) { subdir.mkdirs(); }'。错误的代码。那应该是: if (!subdir.exists()) { if (!subdir.mkdirs()) return null;} 但是这个地方的 mkdirs 是不合逻辑的,因为你会去阅读文件。仅当您要创建文件时才需要 Mkdirs。
  • '我知道“is”是空的,因为有一个 IOException 这样做:'。如果那里有 IOException,那么你应该从那里返回。现在您的代码运行得更远了,这当然是不合逻辑的。

标签: android ioexception fileinputstream bufferedinputstream


【解决方案1】:

您的问题可能是您没有关闭输入流。 文件描述符和流是有限的资源,使用完后释放它们很重要。

通常在 finally 块中完成,例如:

InputStream inputStream = null;
try 
{
    ... use your input stream
}
catch (IOException e)
{
    Log.e(TAG, e.getMessage(), e);
}
finally
{
    if (inputStream != null)
    {
        try
        {
            inputStream.close();
        }
        catch (IOException e)
        {
            Log.e(TAG, e.getMessage(), e);
        }
    }
}

【讨论】:

  • 这可能是问题所在,因为我没有关闭该输入流。我会试试这个,让你知道。无论如何,即使之前在该应用程序中没有打开其他输入流,不关闭该输入流也可能是一个问题?
猜你喜欢
  • 2014-10-25
  • 1970-01-01
  • 1970-01-01
  • 2020-11-30
  • 2012-04-27
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 2017-09-21
相关资源
最近更新 更多