在不同的机器上对同一文件进行不同的编码,即使编码是在读取文件时由 Java 代码显式设置的

different encoding for the same file on different machines even though the encoding is explicitly set by java code when reading the file

提问人:anonimos 提问时间:5/18/2023 最后编辑:anonimos 更新时间:5/22/2023 访问量:136

问:

我有一个文件,我的 java 代码在作业中读取,并在以下行中将编码设置为 UTF8:

LineNumberReader fin = new LineNumberReader(new InputStreamReader(new FileInputStream(mutationInputFileName), StandardCharsets.UTF_8));

在这一行之后,我检查了编码:detectEncoding(mutationInputFileName);

当我在 Mac 上本地运行作业时,文件的编码是 UTF8。当我在部署机器上运行代码时,代码是 ASCII。 我正在使用 tika 来检测文件编码:

public void detectEncoding(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             BufferedInputStream bis = new BufferedInputStream(fis);
             InputStreamReader isr = new InputStreamReader(bis)) {

            String encoding = isr.getEncoding();
            System.out.println("Detected encoding of file: " + filePath + " is : " + encoding);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

我添加了:

System.out.println("System encoding: "+System.getProperty("file.encoding"));

要查看更多信息,在我的本地机器上它是 STIL UTF8,在部署机器上它是: 系统编码:ANSI_X3.4-1968。部署机器使用 linux,我在两台机器上都使用 java 8。

更奇怪的是,如果在终端中我检查编码:本地计算机上的文件 -bi text1.txt 说:“常规文件”,但在部署的版本上:“文本/普通;字符集=utf-8”。 我设法在部署的机器上将编码设置为 UTF8,方法是给

-Dfile.encoding=UTF-8

作为运行类时程序的参数。

知道为什么 LineNumberReader fin = new LineNumberReader(new InputStreamReader(new FileInputStream(mutationInputFileName), StandardCharsets.UTF_8)) 没有在部署机器上将编码设置为 utf-8 吗?

-- 添加更多信息 我说的是同一个文件,比方说 file1.txt。我已从部署计算机下载了文件。此文件是由我无法访问的另一个进程创建的。步骤如下:

  1. LineNumberReader fin = new LineNumberReader(new InputStreamReader(new FileInputStream(mutationInputFileName), StandardCharsets.UTF_8));-- 在这里,我希望 contet 文件采用 UTF8 格式
  2. detectEncoding(mutationInputFileName);
  3. 从文件中提取信息:使用 fin.lines() 和 String[] cols = line.split(TAB_SEPARATOR, -1);以获取列。我对 cols[0] 感兴趣,它可能具有特殊字符,例如 ï¿1/2ï¿1/2。
  4. 将签名编码为 MD5
String signature = encodeAsMD5(signatureBeforeEncoding)

其中 signatureBeforeEncoding 为 col[0] 和 :

    public static String encodeAsMD5(String value) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        byte[] messageDigest = md.digest(value.getBytes());
        BigInteger number = new BigInteger(1, messageDigest);
        return number.toString(16);
    }

我在本地机器上得到的签名与开发不同。如果我通过,我会得到相同的签名

-Dfile.encoding=UTF-8

作为运行类时程序的参数。

Java 编码 UTF-8 ASCII Apache Tika

评论

3赞 SedJ601 5/18/2023
编码检测不是 100%。也是 的子集,所以应该不会有任何问题。运行测试以确保一切正常。编码可能令人头疼。每个人都建议阅读这篇文章。祝你好运!ASCIIUTF8
2赞 SedJ601 5/18/2023
我认为您不必担心机器编码。我认为您只需要知道文件编码。如果您知道这一点,请使用文件编码进行阅读。您可以写入您喜欢的任何编码,前提是您进行了适当的转换。我建议你继续使用.UTF8
1赞 g00se 5/19/2023
问题是在文件中,我有诸如TRï¿1/2ï¿1/2之类的行看起来已经像垃圾了......而且您没有向我们展示您是如何生成 sig(读取操作)的,因此很难提供帮助
3赞 Basil Bourque 5/19/2023
您的问题可能是文件写入,而不是文件读取。直到最近,Java 文件写入的字符编码默认为主机操作系统的默认值。在 Java 18+ 中,UTF-8 是大多数用途的默认值。我在您的问题中没有看到任何关于文件创建的披露。由于缺乏调试细节,我投票关闭。
2赞 g00se 5/19/2023
在不指定编码的情况下也很危险String.getBytes()

答:

0赞 anonimos 5/22/2023 #1

非常感谢您的回答。你是对的,问题出在编码方法上,特别是.将行更改为 : 做了诀窍,因此无需将编码传递给 JVM。byte[] messageDigest = md.digest(value.getBytes());byte[] messageDigest = md.digest(value.getBytes(StandardCharsets.UTF_8));