当解压缩文件时,FileOutputStream会抛出FileNotFoundException异常。

7

我正在使用从谷歌找到的一个类来解压缩.zip文件。.zip包含文件和文件夹。问题在于FileOutputStream抛出了FileNotFoundException,但是文件应该是从.zip文件中取出的,那么它之前怎么可能存在呢?
以下是我在AsyncTask中使用的代码:

@Override
protected Boolean doInBackground(String... params) {
    try {

        String zipFile = Path + FileName;

        FileInputStream fin = new FileInputStream(zipFile);
        ZipInputStream zin = new ZipInputStream(fin);
        ZipEntry ze = null;
        while ((ze = zin.getNextEntry()) != null) {

            if (ze.isDirectory()) {
                dirChecker(ze.getName());
            } else {
                FileOutputStream fout = new FileOutputStream(Path
                        + ze.getName()); // <-- crashes here
                while ((length = zin.read(buffer)) > 0) {
                    fout.write(buffer, 0, length);
                    publishProgress(length);

                }

                zin.closeEntry();
                fout.close();
            }

        }
        zin.close();
    } catch (Exception e) {
        mProgressDialog.dismiss();
        return false;
    }

    return true;
  }

另一个下载 .zip 文件的 AsyncTask

@Override
protected Boolean doInBackground(String... params) {
      try {
          URL url = new URL(params[0]);
          URLConnection conexion = url.openConnection();

          conexion.connect();

          int lenghtOfFile = conexion.getContentLength();
          File f = new File(Path+FileName);
          if(!f.exists())
          {
              f.mkdirs();
              if(!f.createNewFile())
              {
                  f.delete();
                  f.createNewFile();
              }
          }

          InputStream input = new BufferedInputStream(url.openStream());
          OutputStream output = new FileOutputStream(Path+FileName);

          byte data[] = new byte[1024];

          long total = 0;

          while ((count = input.read(data)) != -1) {
              total += count;
              publishProgress((int)((total*100)/lenghtOfFile));
              output.write(data, 0, count);
          }

          output.flush();
          output.close();
          input.close();
          return true;
      } catch (Exception e)     
      {
        e.printStackTrace();
        e.getCause();
        return false;
      }

我再次遇到了FileNotFoundExcpetion并收到(是一个目录)的错误消息!


1
路径的内容是什么?可能缺少尾随的“/”吗? - beny23
7个回答

17

FileOutputStream如果涉及的文件夹不存在,则会抛出FileNotFoundException异常。我在这里没有看到任何目录创建代码,甚至没有检查是否存在Path的代码,所以这可能就是问题所在。


但是文件和文件夹会从.zip文件中提取出来... .zip文件中有很多文件,所以我应该在提取之前手动创建所有文件吗!我检查了目录(dirChecker)... - Omar

8
我再次遇到了FileNotFoundException错误,错误信息显示是目录(is a directory)。
File f = new File(Path+FileName);
f.mkdirs();

试着使用

File directory = new File(Path);
directory.mkdirs();

然后

File file = new File(directory, FileName);

代替你的代码。

请问您能告诉我为什么这个回答没有解决问题吗?根据http://stackoverflow.com/help/how-to-answer的说明,我认为我的回答也可以解决问题,只是来得有些晚了 :) - yseven
这是一个不错的回答。如果你查看我留言时的时间戳,它在你第一次发布此回答之后。那个版本格式差,指向不清。 - Dave Alperovich
@jvperrin 原始编辑得非常好。我建议你学习他和JonathanLeffler对你的答案所做的改变,以增强它 ;) - Dave Alperovich
是的,抱歉我的基本markdown使用不好。正在改进中 :) - yseven

3
你的第一个版本依赖于你没有发布的dirChecker()函数,但它要么不能正确工作,要么你的ZIP文件根本不包含目录条目,这是完全合法的,所以你不应该依赖于它们存在。

你的第二个版本更好,但你不需要所有这些东西:

 File f = new File(Path+FileName);
          if(!f.exists())
          {
              f.mkdirs();
              if(!f.createNewFile())
              {
                  f.delete();
                  f.createNewFile();
              }
          }

你只需要这个:
File f = new File(Path, FileName);
f.getParentFile().mkdirs();

其他事情会自然而然地发生。

2

这里的问题是由于所给定的zip文件或目录嵌套了zip文件或目录引起的。如果所给定的ZipEntry是一个目录,则需要创建该目录并跳过使用FileOutputStream进行写入。

使用zipEnrty.isDirectory()检查所给定的zipEntry是否为目录,并使用zipEntry.mkDirs()创建目录,然后继续下一个zipEntry而不使用fileOutputStream进行写入。

以下是解压缩zip文件的全部代码:

import java.io.*;
import java.util.zip.*;

public class Unzip
{
    public static void main (String args[])
    {
        try
        {
            final int BUFFER = 1024;
            int count;
            byte data[] = new byte[BUFFER];
            String path="res/Example.zip";

            BufferedOutputStream bufferedOutputStream = null;
            FileInputStream fileInputStream = new FileInputStream(path);
            ZipInputStream zipInputStream = new ZipInputStream(new  BufferedInputStream(fileInputStream));
            ZipEntry zipEntry;

            while((zipEntry = zipInputStream.getNextEntry()) != null)
            {
                System.out.println("Extracting: " +zipEntry);
                File file=new File(zipEntry.getName());
                if(zipEntry.isDirectory())
                {
                    file.mkdirs();
                    continue;
                }
                FileOutputStream fileOutputStream = new     FileOutputStream(file,false);
                bufferedOutputStream = new BufferedOutputStream(fileOutputStream, BUFFER);

                while ((count = zipInputStream.read(data, 0, BUFFER))!= -1)
                bufferedOutputStream.write(data, 0, count);

                bufferedOutputStream.flush();
                bufferedOutputStream.close();
            }
            zipInputStream.close();
        } 
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

完美的答案! - J.zhou

0

FileOutputStream构造函数的javadocs中

抛出:
FileNotFoundException - 如果文件存在但是是目录而不是常规文件,不存在但无法创建,或由于任何其他原因无法打开

通常,如果您没有权限创建文件或文件系统的某个部分是只读的,则会发生FileNotFoundException(尽管我不确定在Android中这种情况适用的程度)


我正在尝试写入外部SD卡,我已经使用了权限(Write_External_Sd..),所以我可以在那里写入。 - Omar

-1

我曾经使用以下代码从应用程序小部件写入内部和外部Android存储器:

        URL adr = new URL(cleanUrl);


        HttpURLConnection urlConnection = (HttpURLConnection) adr.openConnection();

        urlConnection.setRequestMethod("GET");
        urlConnection.setDoOutput(true);
        urlConnection.setReadTimeout(5000);

        urlConnection.connect();

        File file = new File(path, name);

        FileOutputStream fileOutput = new FileOutputStream(file);

        InputStream inputStream = urlConnection.getInputStream();

        byte[] buffer = new byte[1024];
        int bufferLength = 0; 
        while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
            fileOutput.write(buffer, 0, bufferLength);
        }
        fileOutput.flush();

        fileOutput.close();

路径是:

        path = mContext.getFilesDir();

或者

        path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

并且

        path.mkdirs(); 

在这两种情况下,我都遇到了一个FileNotFoundException和一个长度为零的创建文件。
我已经使用以下函数成功地向Android内存的两种类型中写入了数据:
   protected InputStream get(String url) throws ClientProtocolException, IOException {

    final HttpClient client = new DefaultHttpClient();

    HttpGet getRequest = new HttpGet(url);

    HttpResponse response = client.execute(getRequest);
    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
        return null;
    }


    final HttpEntity entity = response.getEntity();
    if (entity != null) {
        try {
            return entity.getContent();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    return null;
}

还有以下用法:

          File file = new File(path, name);

        FileOutputStream fileOutput = new FileOutputStream(file);
        InputStream inputStream = get(cleanUrl);            

        byte[] buffer = new byte[1024];
        int bufferLength = 0;
        while ( (bufferLength = inputStream.read(buffer)) > 0 ) {

            fileOutput.write(buffer, 0, bufferLength);
        }
        fileOutput.flush();

        fileOutput.close();

与此无关。问题是关于ZIP文件的。 - user207421

-2
从清单中删除“android:maxSdkVersion =” 18“”
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
   android:maxSdkVersion="18"/>

你在清单文件中声明了。

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

即使他这样做了,但没有任何证据表明他确实这样做了,你仍需要解释为什么这会解决问题,而事实并非如此。 - user207421
我在将图片和视频下载到SD卡时遇到了相同的问题。所以我只是从清单中删除了android:maxSdkVersion="18"。现在它可以正常工作了。 - Muthukumar Subramaniam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接