java - 如何使用 Java 将一个字符串切割成 1 兆字节的子字符串?

标签 java

我想出了以下几点:

public static void cutString(String s) {
    List<String> strings = new ArrayList<>();
    int index = 0;
    while (index < s.length()) {
        strings.add(s.substring(index, Math.min(index + 1048576, s.length())));
        index += 1048576;
    }
}

但我的问题是,使用 UTF-8 某些字符并不完全占用 1 个字节,因此使用 1048576 告诉在哪里剪切字符串不起作用。我正在考虑使用 Iterator,但这似乎效率不高。对此最有效的解决方案是什么?字符串可以小于 1 Mb 以避免字符切片,但不能大于 1 Mb!

最佳答案

快速、不安全的破解

您可以使用 s.getBytes("UTF-8") 获取一个数组,其中包含每个 UTF-8 字符使用的实际字节数。像这样:

System.out.println("¡Adiós!".getBytes("UTF-8").length);
// Prints: 9

一旦有了它,只需将字节数组拆分为长度为 1048576 的 block ,然后使用 new String(chunk, "UTF-8").

但是,通过这样做,您可以在 block 的开头或结尾断开多字节字符。假设第 1048576 个字符是一个 3 字节的 Unicode 字符:第一个字节将进入第一个 block ,另外两个字节将被放入第二个 block ,从而破坏编码。

正确的方法

如果可以放宽“1 MB”的要求,可以采取更安全的方法:将字符串拆分为 1048576 个字符(不是字节)的 block ,然后使用 getBytes 测试每个 block 的实际长度, 根据需要从末尾删除字符,直到实际大小等于或小于 1 MB。

这是一个不会打断字符的实现,代价是让一些行小于给定的大小:

public static List<String> cutString(String original, int chunkSize, String encoding) throws UnsupportedEncodingException {
    List<String> strings = new ArrayList<>();
    final int end = original.length();
    int from = 0, to = 0;
    do {
        to = (to + chunkSize > end) ? end : to + chunkSize; // next chunk, watch out for small strings
        String chunk = original.substring(from, to); // get chunk
        while (chunk.getBytes(encoding).length > chunkSize) { // adjust chunk to proper byte size if necessary
            chunk = original.substring(from, --to);
        }
        strings.add(chunk); // add chunk to collection
        from = to; // next chunk
    } while (to < end);
    return strings;
}

我用 chunkSize = 24 测试了它所以你可以看到效果。它应该适用于任何其他尺寸:

    String test = "En la fase de maquetación de un documento o una página web o para probar un tipo de letra es necesario visualizar el aspecto del diseño. ٩(-̮̮̃-̃)۶ ٩(●̮̮̃•̃)۶ ٩(͡๏̯͡๏)۶ ٩(-̮̮̃•̃).";

    for (String chunk : cutString(test, 24, "UTF-8")) {
        System.out.println(String.format(
                "Chunk [%s] - Chars: %d - Bytes: %d",
                chunk, chunk.length(), chunk.getBytes("UTF-8").length));
    }
    /*
    Prints:
        Chunk [En la fase de maquetaci] - Chars: 23 - Bytes: 23
        Chunk [ón de un documento o un] - Chars: 23 - Bytes: 24
        Chunk [a página web o para pro] - Chars: 23 - Bytes: 24
        Chunk [bar un tipo de letra es ] - Chars: 24 - Bytes: 24
        Chunk [necesario visualizar el ] - Chars: 24 - Bytes: 24
        Chunk [aspecto del diseño. ٩(] - Chars: 22 - Bytes: 24
        Chunk [-̮̮̃-̃)۶ ٩(●̮̮] - Chars: 14 - Bytes: 24
        Chunk [̃•̃)۶ ٩(͡๏̯͡] - Chars: 12 - Bytes: 23
        Chunk [๏)۶ ٩(-̮̮̃•̃).] - Chars: 14 - Bytes: 24
     */

另一项使用 3 MB 字符串的测试,就像您在评论中提到的那样:

    String string = "0123456789ABCDEF";
    StringBuilder bigAssString = new StringBuilder(1024*1024*3);
    for (int i = 0; i < ((1024*1024*3)/16); i++) {
        bigAssString.append(string);
    }
    System.out.println("bigAssString.length = " + bigAssString.toString().length());
    bigAssString.replace((1024*1024*3)/4, ((1024*1024*3)/4)+1, "á");

    for (String chunk : cutString(bigAssString.toString(), 1024*1024, "UTF-8")) {
        System.out.println(String.format(
                "Chunk [...] - Chars: %d - Bytes: %d",
                chunk.length(), chunk.getBytes("UTF-8").length));
    }
    /*
    Prints:
        bigAssString.length = 3145728
        Chunk [...] - Chars: 1048575 - Bytes: 1048576
        Chunk [...] - Chars: 1048576 - Bytes: 1048576
        Chunk [...] - Chars: 1048576 - Bytes: 1048576
        Chunk [...] - Chars: 1 - Bytes: 1
     */

关于java - 如何使用 Java 将一个字符串切割成 1 兆字节的子字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43499976/

相关文章:

java - 如何在 JASPIC 中保存经过身份验证的用户?

java - 接口(interface)和动态方法调度

java - 在menu.xml中使用actionLayout时android中的NullPointerException

没有用逗号分隔的 Java JPA Left Join

java - 在自定义记录器上设置记录级别似乎有味道

java - FetchType.LAZY 不起作用 - Hibernate 和 Criteria

java - 找不到 JDBC 驱动程序

java - 生成 zip 中包含 POI 的 xlsx 文件

java - 为什么 "instanceof"不工作?

java - 为什么我的 spring 应用程序不断打开与云图集 mongoDB 的新连接?