【问题标题】:BufferedReader readLine returns nullBufferedReader readLine 返回 null
【发布时间】:2019-04-16 20:38:51
【问题描述】:

我有一个 zip 文件,其中包含我想要阅读的 9 个文件。于是我实现了以下功能:

public static Map<String, BufferedReader> unzipFile(InputStream zippedFile) throws IOException {
  ZipInputStream zipInputStream = new ZipInputStream(zippedFile);
  HashMap<String, BufferedReader> result = new HashMap<>(9);
  for (ZipEntry zipEntry = zipInputStream.getNextEntry(); zipEntry != null; zipEntry = zipInputStream.getNextEntry()) {
    if (zipEntry.isDirectory()) {
      continue;
    }
    result.put(zipEntry.getName(), new BufferedReader(new InputStreamReader(zipInputStream)));
  }
  return result;
}

同一类中的其他签名(调用相同的方法):

  public static Map<String, BufferedReader> unzipFile(String zippedFile) throws IOException {
    return unzipFile(new File(zippedFile));
  }

  public static Map<String, BufferedReader> unzipFile(File zippedFile) throws IOException {
    return unzipFile(new FileInputStream(zippedFile));
  }

我的想法是获取从此方法返回的Map,并能够在我的代码的其他地方读取它。问题是每次我在这个方法中在for循环之外调用result.get("filename").readLine(),它都会返回null

这里是此方法的简单单元测试 - 目前在最后一个 Assert.assertNotNull 中失败:

  @Test
  public void unzipFileTest() throws Exception  {
    Map<String, BufferedReader> result = FileHandlerUtility.unzipFile(TestUtil.FILE_SAMPLE_NAME);
    Assert.assertNotNull(result);
    Assert.assertEquals(result.size(), 9);
    Assert.assertNotNull(result.get("Car.txt"));
    Assert.assertNotNull(result.get("Client.txt"));
    Assert.assertNotNull(result.get("Client.txt").readLine());
  }

我想可能与创建的变量的范围有关,因为在调试时,我注意到我可以在for 循环中获取文件的内容。但是,我不想将这种 zip 提取方法与获取内容并解析它的方法混合使用。另外,我不想将提取的文件保存到光盘并稍后重新打开。

那么,我怎样才能用BufferedReaders 填充这个Map,在readLine 调用上不会返回null?

【问题讨论】:

  • 测试中调用的方法接受了一些看起来像字符串的东西;此处显示的方法采用 InputStream。请显示字符串重载,因为您在此处显示的方法无法返回 null。
  • 添加了您要求的内容,@AndyTurner
  • 我对我的示例进行了大量编辑,以使其适用于您的 BufferedReader 要求。干杯

标签: java file zip bufferedreader file-read


【解决方案1】:

ZipInputStream

每次迭代入口指针时,都会丢失入口指针,因为每个 ZipInputStream 对象只允许一个流。

try (ZipInputStream is = new ZipInputStream(Zippy.class.getResourceAsStream("file.zip"))) {
            ZipEntry entry;
            while ((entry = is.getNextEntry()) != null) {
                if (!entry.isDirectory()) {
                    // do your logic here (get the entry name)
                }                
                is.closeEntry();
        }
    }

来自 javadocs:

closeEntry()-Closes the current ZIP entry and positions the stream for reading the next entry.

getNextEntry() - Reads the next ZIP file entry and positions the stream at the beginning of the entry data.

基本上,您在任何给定时间只能打开一个条目。

所以如果你想做你正在做的事情,你能做的最好的就是保存 zip 条目的名称并遍历 ZipInputStream 以将指针移动到正确的位置,然后你可以使用 ZipInputStream.read()获取字节。

压缩文件

如果您可以使用 ZipFile 对象(而不是 ZipInputStream),您就可以做您想要完成的事情。

 static void loadMap() throws IOException {
    ZipFile file = new ZipFile("testzip.zip");
    Enumeration<? extends ZipEntry> entries = file.entries();
    while (entries.hasMoreElements()) {
        ZipEntry entry = entries.nextElement();
        if (!entry.isDirectory()) {
            streamMap.put(entry.getName(), new BufferedReader(new InputStreamReader(file.getInputStream(entry))));
        }

    }

}

public static void main(String[] args) throws IOException {
    loadMap();

    Iterator<BufferedReader> iter = streamMap.values().iterator();
    while (iter.hasNext()) {            
        BufferedReader reader = iter.next();
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
}


OUTPUT:
file 2: First line!
file 2: Second Line!
file 1: First line!
file 1 : Second Line!
BUILD SUCCESSFUL (total time: 0 seconds)

您只需要记住保存 zip 文件引用并在完成后致电 file.close();

【讨论】:

  • 我在ZipInputStream Javadocs 上没有找到任何说明在任何给定时间只允许一个条目的内容。但是你的解释很有道理,对我帮助很大!谢谢!
猜你喜欢
  • 2016-01-03
  • 2014-09-26
  • 1970-01-01
  • 2016-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-09
相关资源
最近更新 更多