2015-11-06 66 views
4

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

这是他送我的错误日志:

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"))); 

我明白,这是因为“是”是空的,我应该抓住这种情况,以避免应用程序崩溃(我将修复t他在我的下一个版本)。

编辑3:你是对的,greenapps,我会检查是否为null之前使用它,在其他情况下,我不会使用它。

而且据我所知,“是”为空,因为有一个IOException异常这样做:

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

编辑4:当然,如果这给了我一个IOException异常我将不得不改变我的代码,使一个完成不同的事情。

而我无法在Internet上找到原因,因此这两行代码可能会抛出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); 
      } 
     } 
    } 
} 

我的测试是正常工作了,但用户告诉我,他看到了“解析文件时出错”消息,所以它还没有失败。

我还能检查什么?

+0

你指定你的清单里面的“READ_EXTERNAL_STORAGE”权限?如果您的客户使用带有API 19+的手机,并且不使用“WRITE_EXTERNAL_STORAGE”,则需要此选项。 此外,您可以尝试在您的赋值行和chech中设置断点,以确定变量是否具有预期值。 – localhorst

+0

嗨!我在Android清单中拥有WRITE_EXTERNAL_STORAGE权限,所以我想这没问题。 – Wonton

+0

'明白这是因为“是”是空的,我应该抓住这种情况,以避免应用程序崩溃'。不,你应该在使用它之前检查是否为空。如果是的话,不要使用它。 – greenapps

回答

0

这可能是你的问题是你没有关闭你的输入流。 文件描述符和流是有限的资源,当你完成它们时释放它们非常重要。

通常在做了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); 
     } 
    } 
} 
+0

这可能是问题,因为我没有关闭该输入流。我会试试这个,让你知道。无论如何,即使没有其他输入流在该应用中被打开之前,没有关闭该输入流可能会成为一个问题? – Wonton