将文件放在linux服务器上时,标头中ObjectStream的幻数已更改

时间:2019-05-08 06:35:04

标签: java json linux objectinputstream objectoutputstream

希望您一切都好。 自昨天以来,我发生了一件奇怪的事情。

我有以下代码用于保存JSON。

 public static boolean saveCacheJson(String pathToCache, JSONObject json) {
        boolean isSaveSuccess = false;
        ObjectOutputStream outputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            File file = new File(pathToCache);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                new FileWriter(file);
            } else {
                file.delete();
            }
            fileOutputStream = new FileOutputStream(pathToCache);
            outputStream = new ObjectOutputStream(fileOutputStream);
            outputStream.writeObject(json.toString());
            isSaveSuccess = true;
        } catch (IOException e) {
            IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().sendLog(e);

            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
            } catch (Exception e1) {
                IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().sendLog(e1);
                e1.printStackTrace();
            }
            try {
                fileOutputStream.close();
            } catch (Exception e1) {
                IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().sendLog(e1);
                e1.printStackTrace();
            }
        }
        return isSaveSuccess;
    }

以及以下用于阅读的代码。

public static JSONObject getCacheJson(String pathToCache, boolean throwException) throws Exception {
        JSONObject result = null;
        String resultString;
        ObjectInputStream inputStream = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(pathToCache);
            inputStream = new ObjectInputStream(fileInputStream);
            resultString = (String) inputStream.readObject();
            result = new JSONObject(resultString);
        } catch (ClassNotFoundException | IOException | JSONException e) {
            e.printStackTrace();
            if (throwException && e instanceof FileNotFoundException) {
                throw e;
            }
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }

        return result;
    }

我正在通过saveCacheJson编写JSON,然后将文件放入服务器(Linux),然后我的“前端”部分下载并尝试读取。

从昨天开始,我开始收到以下异常。

java.io.StreamCorruptedException: invalid stream header:

经过研究并试图了解发生了什么,我发现了以下内容。

ObjectOutputStream类中有一个MAGIC_NUMBER,用于标题。

protected void writeStreamHeader() throws IOException {
        this.bout.writeShort(-21267);
        this.bout.writeShort(5);
    }

然后,在ObjectInputStream类中,调用以下方法。

protected void readStreamHeader() throws IOException, StreamCorruptedException {
        short var1 = this.bin.readShort();
        short var2 = this.bin.readShort();
        if (var1 != -21267 || var2 != 5) {
            throw new StreamCorruptedException(String.format("invalid stream header: %04X%04X", var1, var2));
        }
    }

在这里抛出异常。

因此,我打开了在本地计算机(Mac OS)上写入的文件,并找到了以下的前2个字节

¨Ì

然后我在终端中尝试了以下操作。

hexdump myfile

,发现前2个字节正确。 就是这个。

ac ed ... 

因此,我尝试对下载的文件(从我之前放过的Linux服务器)执行相同的操作,发现前2个字节是错误的。 因此,我检查了流程,发现在将文件复制到服务器期间它们已更改。

总体上来说这很奇怪,但是最奇怪的是它已经运行了大约10天。我记得我的服务器没有任何变化。

所以,我的主要问题是

在上载到LINUX服务器期间更改流标头的任何想法?

谢谢。

更新

在上传之前文件中的前2条短裤是

ac ed 00 05 ...

哪个是对的

从Mac上传到Linux之后,文件中的前2个短裤是

bfef efbd ...

错了。

更新2。

来自正确文件的结果。

0000000 ac ed 00 05 7c 00 00 00 00 00 0f 26 fe 7b 22 64
0000010 65 22 3a 7b 22 6e 70 63 22 3a 5b 7b 22 63 6f 64
0000020 65 22 3a 22 64 65 22 2c 22 6e 70 63 5f 69 64 22
0000030 3a 32 2c 22 6c 61 6e 67 5f 69 64 22 3a 36 2c 22
0000040 69 64 22 3a 31 32 2c 22 6c 61 6e 67 75 61 67 65
0000050 5f 69 64 22 3a 36 2c 22 64 69 61 6c 6f 67 73 22
0000060 3a 5b 22 53 63 68 61 75 20 6d 61 6c 2c 20 64 61
0000070 73 20 69 73 74 20 49 72 69 73 2c 20 64 65 72 20
0000080 42 6f 74 65 20 64 65 72 20 47 c3 b6 74 74 65 72
0000090 2e 20 53 69 65 20 68 61 74 20 75 6e 73 20 6d 61
..........

来自错误的文件。

0000000 ef bf bd ef bf bd 00 05 7c 00 00 00 00 00 0f 26
0000010 ef bf bd 7b 22 64 65 22 3a 7b 22 6e 70 63 22 3a
0000020 5b 7b 22 63 6f 64 65 22 3a 22 64 65 22 2c 22 6e
0000030 70 63 5f 69 64 22 3a 32 2c 22 6c 61 6e 67 5f 69
0000040 64 22 3a 36 2c 22 69 64 22 3a 31 32 2c 22 6c 61
0000050 6e 67 75 61 67 65 5f 69 64 22 3a 36 2c 22 64 69
0000060 61 6c 6f 67 73 22 3a 5b 22 53 63 68 61 75 20 6d
0000070 61 6c 2c 20 64 61 73 20 69 73 74 20 49 72 69 73
0000080 2c 20 64 65 72 20 42 6f 74 65 20 64 65 72 20 47
0000090 c3 b6 74 74 65 72 2e 20 53 69 65 20 68 61 74 20

2 个答案:

答案 0 :(得分:2)

看来,您用于将数据从Mac传输到Linux的任何事物都在尝试进行某种重新编码,可能涉及UTF-8或UTF-16,但是我无法确切确定它在试图做什么。

还有一个字节顺序问题,因为它反转了16位字的字节顺序。注意在正确的十六进制的第一行上,序列0x0f26。在乱码文件中,顺序为0x260f

我建议您仔细检查将文件从Mac传输到Linux的过程,并尝试找到控制文件编码和字节顺序的任何选项。

更新

我知道了。首先,转换器确定某些字符无效,并用Unicode代码点0xfffd或替换字符替换它们。然后,它将结果流编码为UTF-8。 UTF-8中0xfffd的编码为0xefbfbd

AC ED --(replace)-> FFFD FFFD --(utf8 encode)-> EF BF BD EF BF BD

无论处理什么过程,传输都假定输入为UTF-8(这是不正确的),数据流为二进制。字节值0xAC0xED在UTF-8中无效,因此将它们替换为以UTF-8编码的Unicode替换字符。碰巧代表无效UTF-8字节的其他二进制值也将被替换。

答案 1 :(得分:0)

好的,我找到了导致问题的原因。不知道为什么,但是找到了解决方法。

我将mypath/myfile.txt用作pathToCache方法的saveCacheJson参数。因此,我发现此问题是由于.txt扩展名造成的。 我完全删除了扩展名,问题解决了。 看来.txt扩展名是原因,因为Mac的系统无法理解该文件是二进制文件,并试图在复制过程中对其内容进行编码。 不知道为什么系统在复制期间完全尝试更改文件的内容))