Java 字节数组替换所有出现的 byte-array/string

Java byte array replace all occurrences of byte-array/string

是否有任何“已经实现”(非手动)的方法来替换字节数组中出现的所有单个 byte-array/string?我有一个案例,我需要创建包含平台相关文本的字节数组(Linux(换行),Windows(回车 return + 换行))。我知道这样的任务可以手动实现,但我正在寻找开箱即用的解决方案。请注意,这些字节数组很大,在我的情况下,解决方案需要在性能方面表现出色。另请注意,我正在处理大量这些字节数组。

我目前的做法:

var byteArray = resourceLoader.getResource("classpath:File.txt").getInputStream().readAllBytes();
byteArray = new String(byteArray)
    .replaceAll((schemeModel.getOsType() == SystemTypes.LINUX) ? "\r\n" : "\n",
                (schemeModel.getOsType() == SystemTypes.LINUX) ? "\n" : "\r\n"
    ).getBytes(StandardCharsets.UTF_8);

由于创建新字符串并使用正则表达式查找匹配项,因此这种方法在性能上并不明智。我知道由于 Windows 编码,手动实现需要查看字节序列。因此,手动实施也需要重新分配(如果需要)。

Appache 通用语言实用程序包含 ArrayUtils 其中包含方法
byte[] removeAllOccurrences(byte[] array, byte element)。是否有任何第三方库包含类似的方法来替换字节数组中的 ALL byte-arrays/strings 事件??

编辑:正如@saka1029 在评论中提到的,我的方法不适用于Windows OS 类型。由于这个错误,我需要坚持使用正则表达式如下:

(schemeModel.getOsType() == SystemTypes.LINUX) ? "\r\n" : "[?:^\r]\n", 
(schemeModel.getOsType() == SystemTypes.LINUX) ? "\n" : "\r\n")

这样,对于 windows 的情况,只搜索前面没有 '\r' 的 '\n' 并用 '\r\n' 替换(正则表达式被修改为在 ' \n' 不要直接在 [^\r]\n 位置,否则也会提取行中的最后一个字母)。这样的工作流程不能用传统的方法实现,因此这个问题是无效的。

如果您正在阅读文本,则应将其视为文本,而不是字节。使用 BufferedReader 逐行阅读,并插入您自己的换行序列。

String newline = schemeModel.getOsType() == SystemTypes.LINUX ? "\n" : "\r\n";

OutputStream out = /* ... */;

try (Writer writer = new BufferedWriter(
        new OutputStreamWriter(out, StandardCharsets.UTF_8));
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(
            resourceLoader.getResource("classpath:File.txt").getInputStream(),
            StandardCharsets.UTF_8))) {

    String line;
    while ((line = reader.readLine()) != null) {
        writer.write(line);
        writer.write(newline);
    }
}

不需要字节数组,而且您只使用了少量内存——容纳遇到的最大行所需的内存量。 (我很少看到一行长度超过 1 KB 的文本,但即使是 1 MB 的内存需求也很小。)

如果您正在“修复”zip 条目,OutputStream 可以是指向新 ZipEntry 的 ZipOutputStream:

String newline = schemeModel.getOsType() == SystemTypes.LINUX ? "\n" : "\r\n";

ZipInputStream oldZip = /* ... */;
ZipOutputStream newZip = /* ... */;

ZipEntry entry;
while ((entry = oldZip.getNextEntry()) != null) {
    newZip.putNextEntry(entry);

    // We only want to fix line endings in text files.
    if (!entry.getName().matches(".*\." +
        "(?i:txt|x?html?|xml|json|[ch]|cpp|cs|py|java|properties|jsp)")) {

        oldZip.transferTo(newZip);
        continue;
    }

    Writer writer = new BufferedWriter(
        new OutputStreamWriter(newZip, StandardCharsets.UTF_8));

    BufferedReader reader = new BufferedReader(
        new InputStreamReader(oldZip, StandardCharsets.UTF_8));

    String line;
    while ((line = reader.readLine()) != null) {
        writer.write(line);
        writer.write(newline);
    }

    writer.flush();
}
    

一些注意事项:

  • 您是否故意忽略 Mac(以及其他既不是 Windows 也不是 Linux 的操作系统)?除了 Windows 之外,您应该假设所有内容都为 \n。即schemeModel.getOsType() == SystemTypes.WINDOWS ? "\r\n" : "\n"
  • 您的代码包含 new String(byteArray),它假设您的资源字节使用您的程序所在系统的默认字符集 运行。我怀疑这不是你想要的;我已将 StandardCharsets.UTF_8 添加到 InputStreamReader 的构造中以解决此问题。如果您真的想使用默认字符集读取字节,则可以删除第二个构造函数参数。