【问题标题】:StringBufferInputStream Question in JavaJava中的StringBufferInputStream问题
【发布时间】:2010-12-26 04:14:47
【问题描述】:

我想读取输入字符串并将其作为 UTF8 编码字符串返回。所以我在 Oracle/Sun 网站上找到了一个使用 FileInputStream 的示例。我不想读取文件,而是读取字符串,所以我将其更改为 StringBufferInputStream 并使用下面的代码。方法参数jtext,是一些日文文本。 其实这个方法很好用。问题是关于已弃用的代码。我不得不放 @SuppressWarnings 因为 StringBufferInputStream 已被弃用。我想知道是否有更好的方法来获取字符串输入流?可以保持原样吗?我花了很长时间试图解决这个问题,以至于我不想改变任何东西,现在我似乎已经破解了它。

            @SuppressWarnings("deprecation")
    private  String readInput(String jtext) {

        StringBuffer buffer = new StringBuffer();
        try {
        StringBufferInputStream  sbis = new StringBufferInputStream (jtext);
        InputStreamReader isr = new InputStreamReader(sbis,
                                  "UTF8");
        Reader in = new BufferedReader(isr);
        int ch;
        while ((ch = in.read()) > -1) {
            buffer.append((char)ch);
        }

        in.close();
        return buffer.toString();
        } catch (IOException e) {
        e.printStackTrace();
        return null;
        }
    }

我想我找到了一个解决方案 - 有点:

private  String readInput(String jtext) {

        String n;
        try {
            n = new String(jtext.getBytes("8859_1"));
            return n;
        } catch (UnsupportedEncodingException e) {

            return null;
        }
                    }

在我拼命使用 getBytes(UTF8) 之前。但我偶然使用了 Latin-1 "8859_1" 并且它起作用了。为什么它起作用,我无法理解。这是我一步一步做的:

OpenOffice CSV(utf8)------>SQLite(utf8, 显然)------->java 编码为 Latin-1,以某种方式可读。

【问题讨论】:

    标签: java inputstream


    【解决方案1】:

    不推荐使用StringBufferInputStream 的原因是因为它从根本上被破坏了......除了完全由Latin-1 字符组成的字符串之外的任何内容。根据javadoc,它通过简单地切掉前8位来“编码”字符!如果您的应用程序需要正确处理 Unicode 等,您不想使用它。

    如果你想从String 创建一个InputStream,那么正确的做法是使用String.getBytes(...)String 转换为字节数组,然后将其包装在@987654326 中@。 (确保您选择了合适的编码!)。

    但是您的示例应用程序会立即获取InputStream,将其转换为Reader,然后添加BufferedReader 如果这是您的真正目标,那么更简单、更有效的方法就是:

    Reader in = new StringReader(text);
    

    这避免了不必要的字符串编码和解码,以及在这种情况下没有用处的“缓冲”层

    (如果您在文件、网络或控制台流上执行小型 I/O 操作,则缓冲流比无缓冲流更有效。但是对于从内存数据结构提供服务的流,好处是小得多,甚至可能是负数。)

    跟进

    我意识到您现在正在尝试做什么...解决字符编码/解码问题。

    我的建议是尝试明确弄清楚数据库正在传递的字符数据的实际编码,然后确保将 JDBC 驱动程序配置为使用相同的编码。试图通过一种编码和另一种解码来消除错误翻译是不可靠的,只能给你部分纠正问题。

    您还需要考虑字符在进入数据库的过程中被破坏的可能性。如果是这种情况,那么您可能无法解开它们。

    【讨论】:

    • 我不确定是否需要缓冲区,但这是 Oracle 示例中的剪切和粘贴作业,所以我将其保留。我将尝试 String.getBytes(... ) 下次我有机会时(今天不再使用 Android)。感谢您的帮助!
    • 不幸的是 StringReader 没有工作。乱码的字符串没有改变。将字符串更改为字节的类会很好。所以我想我会坚持使用 StirngBufferInptStream,直到找到更好的东西。我确实发现数据库以 UTF8 编码。
    • 如果您知道数据库将字符编码为 UTF-8,您现在需要确保将 JDBC 驱动程序(或其他)配置为使用 UTF-8。然后你就不需要通过重新编码来尝试“修复”字符串了。
    • 嗯,这就是事情变得困难的地方。 (我正在使用带有 SQLite 的 Android)。问题是 SQlite 说它将我的日文文本存储在 UTF8 中,但它在数据库中是乱码。即使同一个 CSV 包含英文和日文文本,英文文本也不会出现乱码。但我很想把它留在原处,因为我在 SBIS 之后对日文文本进行了两次、三次检查,一切都很好。
    【解决方案2】:

    这是你想要做的吗?这是similar question 的先前答案。我不确定为什么要将字符串转换为完全相同的字符串。

    Java String 包含一个字符序列,其中每个字符代表一个 Unicode 数字。所以可以用两个不同的字节序列构造同一个字符串,一个用UTF-8编码,另一个用US-ASCII编码。

    如果你想把它写入文件,你可以随时用String.getBytes("encoder");转换它

    private static String readInput(String jtext) {
        byte[] bytes = jtext.getBytes();
        try {
            String string = new String(bytes, "UTF-8");
            return string;
        } catch (UnsupportedEncodingException ex) {
            // do something
            return null;
        }
    }
    

    更新

    这是我的假设。

    根据您的评论,您的 SQLite DB 使用一种编码存储文本值,即 UTF-16。由于某种原因,您的 SQLite APi 无法确定它使用什么编码将 Unicode 值编码为字节序列。

    因此,当您使用 SQLite API 中的 getString 方法时,它会从您的数据库中读取一组字节,并使用不正确的编码将它们转换为 Java 字符串。如果是这种情况,您应该使用getBytes 方法并自己重构字符串,即new String(bytes, "encoding used in your DB"); 如果您的数据库以UTF-16 存储,那么new String(bytes, "UTF-16"); 应该是可读的。

    更新

    我不是在谈论 String 类上的 getBytes 方法。我谈到了您的 SQL 结果对象上的 getBytes 方法,例如result.getBytes(String columnLabel).

    ResultSet result = .... // from SQL query
    String readableString = readInput(result.getBytes("my_table_column"));
    

    您需要将readInput 方法的签名更改为

    private static String readInput(byte[] bytes) {
        try {
            // change encoding to your DB encoding.
            // this can be UTF-8, UTF-16, 8859_1, etc.
            String string = new String(bytes, "UTF-8");
            return string;
        } catch (UnsupportedEncodingException ex) {
            // do something, at least return garbled text
            return new String(bytes, "UTF-8");;
        }
    }
    

    无论您在此处设置何种编码使您的 String 可读,它绝对是您在 DB 中的列的编码。这不涉及无法解释的现象,并且您确切地知道您的列编码是什么。

    但最好配置您的 JDBC 驱动程序以使用正确的编码,这样您就不需要使用此 readInput 方法进行转换。

    如果没有编码可以使您的字符串可读,您将需要考虑在将其写入数据库时​​字符被破坏的可能性,正如@Stephen C 所说。如果是这种情况,使用遍历方法可能会导致您在转换过程中丢失一些字符。您还需要在编写过程中解决编码问题。

    【讨论】:

    • 字符串为日文,乱码不可读。它取自 SQlite 数据库,这是我的问题所在。出于某种原因,sqlite 不想阅读日语文本,即使我将输入格式化为 UTF8。我得出的结论是,数据库没有将文本存储为 UTF8,而是以其他方式存储,可能是 UTF16。因此,当我从数据库中读取字符串时(我应该提到我使用的是 Android Java),它是乱码。所以我决定用 UTF8 的 java/android 重新格式化它,嘿,它工作了!也许其中有一些一厢情愿和黑魔法,但它奏效了!
    • 字符编码是一种将字节序列映射到 Unicode 值的方法。如果您的数据库使用 UTF16 存储字节序列,那么当您将其读取为字符串时,您将需要指定 UTF-16 作为编码。如果我理解正确,您的 SQLite API 返回一个字符串,但它没有正确设置编码,这就是您重新编码时它起作用的原因。您可以尝试从数据库中获取字节并使用 new String(bytes, "encoding used in your db");构造你的字符串,即不要使用你的 SQLite getString 方法。
    • 我不知道数据库中使用的编码。它不能是UTF8,因为它是乱码。但是sqlite只知道UTF8和UTF16,所以我猜肯定是UTF16。问题是 OpenOffice 只能将 CSV 文件(用于 DB 导入)格式化为 UTF7/8。
    • 我试过 "new String(bytes, "UTF-16");"但文字是乱码。事实上 getBytes() 不适用于 UTF-8 或 UTF-16。我想我应该坚持使用 StirngBufferINputStream,无论是否弃用。
    • @JJG - StringBufferInputStream 不会“工作”,除非字符是 Latin-1
    【解决方案3】:

    StringReader 类是已弃用的 StringBufferInputStream 类的新替代品。

    但是,您声明您实际想要做的是获取现有的String 并将其编码为 UTF-8 并将其返回。我期望你应该能够更简单地做到这一点。比如:

    s8 = new String(jtext.getBytes("UTF8"));
    

    【讨论】:

    • 感谢您的帮助。我试过你说的,但不幸的是,如果我使用 getBytes(),文本会出现乱码。我不知道为什么。
    • @JJG gigadot 的回答对问题的这方面有更多详细信息。
    猜你喜欢
    • 1970-01-01
    • 2011-01-10
    • 2011-06-28
    • 2015-01-16
    • 2010-12-30
    • 2011-03-08
    • 2016-10-19
    • 2011-09-04
    • 2014-05-01
    相关资源
    最近更新 更多