如何从内存中的流式 zip 文件访问 zipEntry

2024-01-06

我目前正在实现一个电子阅读器库(skyepub http://skyepub.net/)这要求我实现一个方法来检查 zipEntry 是否存在。在他们的演示版本中,解决方案很简单:

public boolean isExists(String baseDirectory,String contentPath) {
    setupZipFile(baseDirectory,contentPath);
    if (this.isCustomFont(contentPath)) {
        String path = baseDirectory +"/"+ contentPath;
        File file = new File(path);
        return file.exists();
    }

    ZipEntry entry = this.getZipEntry(contentPath);
    if (entry==null) return false;
    else return true;       
}

// Entry name should start without / like META-INF/container.xml 

private ZipEntry getZipEntry(String contentPath) {

    if (zipFile==null) return null;

    String[] subDirs = contentPath.split(Pattern.quote(File.separator));

    String corePath = contentPath.replace(subDirs[1], "");

    corePath=corePath.replace("//", "");

    ZipEntry entry = zipFile.getEntry(corePath.replace(File.separatorChar, '/'));

    return entry;

}

正如您所看到的,您可以使用 O(1) 时间访问有问题的 ZipEntrygetZipEntry(contentPath);

但是,就我而言,我无法直接从文件系统读取 zip 文件(出于安全原因,必须从内存中读取)。ifExists实现实际上是通过 zip 文件进行的一次一个条目,直到找到有问题的 zipEntry,以下是相关部分:

try {
        final InputStream stream = dbUtil.getBookStream(bookEditionID);
        if( stream == null) return null;

        final ZipInputStream zip = new ZipInputStream(stream);

        ZipEntry entry;
        do {
            entry = zip.getNextEntry();
            if( entry == null) {
                zip.close();
                return null;
            }
        } while( !entry.getName().equals(zipEntryName));

    } catch( IOException e) {
        Log.e("demo", "Can't get content data for "+contentPath);
        return null;
    }

    return data;

所以如果数据存在,ifExists返回 true,如果为 null,则返回 false。

Question

有没有办法可以在 O(1) 时间内而不是 O(n) 时间内从整个 ZipInputStream 中找到有问题的 zip 条目?

Related

See this https://stackoverflow.com/questions/36768080/reading-a-decrypted-file-into-a-zipinputstream-truncates-first-file-sometimes问题 和this https://stackoverflow.com/a/36797263/766570 answer.


zip 存档中的条目实际上无法在 O(1) 时间内加载。如果我们看一下 a 的结构压缩档案 https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT,它看起来像这样:

  [local file header 1]
  [encryption header 1]
  [file data 1]
  [data descriptor 1]
  ... 
  [local file header n]
  [encryption header n]
  [file data n]
  [data descriptor n]
  [archive decryption header] 
  [archive extra data record] 
  [central directory header 1]
  .
  [central directory header n]
  [zip64 end of central directory record]
  [zip64 end of central directory locator] 
  [end of central directory record]

基本上,有一些带有一些标头的压缩文件以及一个“中心目录”,其中包含有关文件的所有元数据(中心目录标头)。定位条目的唯一有效方法是扫描中央目录(更多信息 https://en.wikipedia.org/wiki/Zip_(file_format)#Structure):

...不得从 ZIP 文件顶部扫描条目,因为只有中央目录指定文件块的开始位置

由于中央目录头没有索引,因此只能获取以下条目:O(n) where n是存档中的文件数。

Update:不幸的是,我知道的所有使用流而不是文件的 zip 库都使用本地文件头并扫描整个流(包括内容)。它们也不能轻易弯曲。避免扫描我发现的整个档案的唯一方法是自己调整库。

更新2:为了您的目的,我冒昧地修改了上述 zip4j 库。假设您以字节数组读取 zip 文件,并且添加了对 zip4j 版本 1.3.2 的依赖项,您可以使用内存头读取器 http://pastebin.com/d3ZcsNYc and 随机字节流 http://pastebin.com/v7ik2frq像这样:

String myZipFile = "...";
byte[] bytes = readFile();
MemoryHeaderReader headerReader = new MemoryHeaderReader(RandomAccessStream.fromBytes(bytes));
ZipModel zipModel = headerReader.readAllHeaders();
FileHeader myFile = Zip4jUtil.getFileHeader(zipModel, myZipFile)
boolean fileIsPresent = myFile != null;

它适用于O(条目数)无需读取整个档案,这应该相当快。我还没有彻底测试它,但它应该让您了解如何根据您的目的调整 zip4j。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从内存中的流式 zip 文件访问 zipEntry 的相关文章

随机推荐

  • Matlab fopen,是否可以有数字文件名?

    我有以下代码 ptol 2 4 8 a ptol 1 fid fopen a r 我需要打开一个文件 该文件由调用的号码确定ptol 即如果ptol 1 2 那么fopen应该打开文件 2 目前我收到错误 文件名无效 我该如何解决 以下代码
  • python - 被pandas条件和/或布尔索引难住了

    我在条件 布尔索引方面遇到问题 我正在尝试使用逻辑填充数据框 dfp 该逻辑以类似形状的数据框 dfs 加上其本身的前一行 dfp 的数据为条件 这是我最近的失败 import pandas as pd dfs pd DataFrame a
  • Shiny Server 自定义 Handlebars.js 模板

    我对handlebars js一点也不熟悉 但我想自定义Shiny Server附带的目录索引模板 具体来说 我想要做的是渲染不同应用程序的缩略图页面 文件 opt shiny server templates directorIndex
  • 内核、内核线程和用户线程之间的区别

    我不确定我是否完全理解上述差异 所以我想自己解释一下 如果我错了 你可以打断我 内核是创建内核线程的初始代码 内核线程是由内核管理的进程 用户线程是进程的一部分 如果您有一个单线程进程 那么整个进程本身就是一个用户线程 用户线程进行系统调用
  • uint8_t、uint16_t、... 的格式说明符?

    如果我有一个整数变量我可以使用sscanf如下所示 使用格式说明符 d sscanf line Value of integer d n my integer 在哪里可以找到格式说明符uint8 t uint16 t uint32 t an
  • 使用 Instant.parse 解析 2018-05-01T00:00:00 日期时出错

    这是我的代码 我用它来使用 Instant parse 解析字符串 String date 2018 05 01T00 00 00 Instant parse date 并低于错误 java time format DateTimePars
  • withCriteria 两级深度关联 eager fetch grails

    我想急切地加载一个结构 在关联链中有两层深度 大致如下 class TopLevel String name LevelOne levelOne class LevelOne String name LevelTwo levelTwo cl
  • 非标准 HTTP 端口源的 URLConnection FileNotFoundException

    我试图使用 Apache AntGet task http ant apache org manual Tasks get html获取我们公司另一个团队生成的 WSDL 列表 他们将它们托管在 weblogic 9 x 服务器上http
  • SSRS:显示逗号而不是点

    我想在我的报告中使用逗号而不是点 我使用了这种格式 Format Fields True Value F2 但这向我展示了一个点 我怎样才能得到逗号 除了 niktrs 回答之外 还可以通过属性窗口设置报告的语言设置
  • Android Room - 具有附加字段的多对多关系

    I have a Many to Many relationship set up on my Room database denoted by the following diagram 我想向 CrossRef 表添加额外的字段 我的问
  • 在 Google Cloud 上的 Docker 上启动 TensorFlow

    我按照此处的说明在 Google Cloud 上的 Docker 上安装 TensorFlow http tensorflow org get started os setup html docker based installation
  • Snowflake:无法使用阶段(S3)- SQL 编译错误:阶段不存在或未授权

    我在 Snowflake 中创建了一个外部舞台 我也尝试过使用公共存储桶 CREATE OR REPLACE stage DATABASE SCHEMA STAGE NAME url s3 bucket CREDENTIALS AWS KE
  • C# web 和 ftp 爬虫库

    我需要一个库 希望是 C 语言 它可以作为网络爬虫来访问 HTTP 文件和 FTP 文件 原则上 我很高兴阅读 HTML 我想将其扩展到 PDF WORD 等 我对初学者的开源软件或至少对文档的任何指示感到满意 Check NCrawler
  • UsbConnection.bulkTransfer 返回“-1”。这是什么意思?

    根据文档 消极反应意味着失败 如何知道出了什么问题 有关于错误类型的完整文档吗 为了更好奇 我正在尝试通过 USB 上传 arduino sketch 首先 我通过关闭 打开 DTR RTS 然后使用 Stk500 协议发送数据来引起引导加
  • noscript 内容是否加载到 bg 中

    即使启用了 javascript html 标签 noscript 是否会在后台加载内容 我有一个随机图像 每次页面加载时都会由 JS 调用 但我希望抓取所有链接 而不仅仅是当前的随机链接 同时 我不希望页面加载速度减慢 因为图像在后台加载
  • jQuery.remove() - 有没有办法在删除对象后将其取回?

    我在这个问题上基本上有同样的问题 Flash 视频仍在隐藏的 div 中播放 https stackoverflow com questions 1806032 flash video still playing on div that i
  • 为列提供多个索引/标题

    我正在使用 pandas 数据帧 这些数据帧本质上是这样的时间序列 level Date 1976 01 01 409 67 1976 02 01 409 58 1976 03 01 409 66 我想要的是级别列的多个索引 标题 如下所示
  • SQL Server 存储过程中的动态数据源

    我有一个包含多个数据库的 SQL Server 我有一个主数据库 其中包含多个包含实体和 ID 号的表 然后 每个实体都有一个与其所有信息相关的数据库 不是表 而是数据库 例如 如果 MAIN 数据库中的实体的 ID 号为 1 则同一 SQ
  • 如何从iPhone文档目录中读取pdf文件?

    目前我正在iPhone应用程序中工作 我在资源文件夹中有一个pdf文件 本地pdf文件 然后我成功读取了该pdf文件 paper pdf 下面我提到了读取本地pdf文件供您参考 Example CFURLRef pdfURL CFBundl
  • 如何从内存中的流式 zip 文件访问 zipEntry

    我目前正在实现一个电子阅读器库 skyepub http skyepub net 这要求我实现一个方法来检查 zipEntry 是否存在 在他们的演示版本中 解决方案很简单 public boolean isExists String ba