Java InputStream.readAllBytes() returns 比写的多

Java InputStream.readAllBytes() returns more than what was written

我有这个代码

    public static void main(String[] args) throws Exception {
        try (PythonInterpreter pi = new PythonInterpreter()) {

            String sourceString = "print 'compiled!'";
            String name = "mymodule";

            // Dress the String as bytes: compiler not v good with encodings.
            InputStream source = new InputStream() {
                ByteBuffer buf = StandardCharsets.US_ASCII.encode(sourceString);
                @Override
                public int read() throws IOException {
                    if (buf.remaining() > 0) {
                        return buf.get() & 0xff;
                    } else {
                        return -1;
                    }
                }
            };

            byte[] javaCode = imp.compileSource(name, source, "<string>");
            String className = name + "$py";

            System.out.println(String.format("Original length: %s", javaCode.length));
            
            PyCode code = BytecodeLoader.makeCode(className, javaCode, "<string>");
            System.out.println(String.format("Code: %s", code));
            pi.exec(code);

            // You can write a file and read it back if you want :)
            byte[] javaCode2 = javaCode.clone();
            
            System.out.println(String.format("Read in length: %s", javaCode2.length));
            
            if (javaCode2.length == javaCode.length){
                System.out.println(String.format("Are equal: %s", Arrays.equals(javaCode, javaCode2)));
            }

            PyCode code2 = BytecodeLoader.makeCode(className, javaCode2, "<file>");
            System.out.println(String.format("Code: %s", code2));
            pi.exec(code2);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

输出

Original length: 2125
Code: <code object <module> at 0x2, file "<string>", line 0>
compiled!
Read in length: 2125
Are equal: true
Code: <code object <module> at 0x3, file "<file>", line 0>
compiled!

一切都很好,但是,当我将单行 javaCode.clone() 交换为写入然后从文件读取时

    public static void main(String[] args) throws Exception {
        try (PythonInterpreter pi = new PythonInterpreter()) {

            String sourceString = "print 'compiled!'";
            String name = "mymodule";

            // Dress the String as bytes: compiler not v good with encodings.
            InputStream source = new InputStream() {
                ByteBuffer buf = StandardCharsets.US_ASCII.encode(sourceString);
                @Override
                public int read() throws IOException {
                    if (buf.remaining() > 0) {
                        return buf.get() & 0xff;
                    } else {
                        return -1;
                    }
                }
            };

            byte[] javaCode = imp.compileSource(name, source, "<string>");
            String className = name + "$py";

            System.out.println(String.format("Original length: %s", javaCode.length));
            
            PyCode code = BytecodeLoader.makeCode(className, javaCode, "<string>");
            System.out.println(String.format("Code: %s", code));
            pi.exec(code);

/// CHANGE STARTS HERE
            OutputStream os =
                    Files.newOutputStream(Paths.get("compiled_code"), StandardOpenOption.CREATE);
            System.out.println(String.format("os: %s", os));
            os.write(javaCode);
            os.close();

            InputStream is =
                    Files.newInputStream(Paths.get("compiled_code"), StandardOpenOption.READ);
            System.out.println(String.format("is: %s", is));
            byte[] javaCode2 = is.readAllBytes();
            is.close();
/// CHANGE ENDS HERE
            
            System.out.println(String.format("Read in length: %s", javaCode2.length));
            
            if (javaCode2.length == javaCode.length){
                System.out.println(String.format("Are equal: %s", Arrays.equals(javaCode, javaCode2)));
            }

            PyCode code2 = BytecodeLoader.makeCode(className, javaCode2, "<file>");
            System.out.println(String.format("Code: %s", code2));
            pi.exec(code2);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

输出变为

Original length: 2125
Code: <code object <module> at 0x2, file "<string>", line 0>
compiled!
os: java.nio.channels.Channels@3533df16
is: sun.nio.ch.ChannelInputStream@14ac77b9
Read in length: 2152
Exception in thread "main" java.lang.ClassFormatError: Extra bytes at the end of class file mymodule$py

我的问题是,为什么 readAllBytes() 给出了一个长度为 2152 的字节数组(比给 os.write() 的多了 27 个字节)?

我检查了一下,javaCode2中的所有字节都是正确的,只要你忽略多余的27就可以了。

额外的是 0 88 0 1 0 89 73 0 90 0 91 0 1 0 89 74 0 92 0 94 0 1 0 89 115 0 95

您可能正在覆盖现有文件,更改为使用截断以及将文件大小重置为零:

Path path = Paths.get("compiled_code");
OutputStream os = Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

但是,使用 Files 的内置调用进行 byte[] 读取和写入会更好 - 节省几行代码,并且可以省略 try-with-resources 流处理或 close() 操作:

Files.write(path, javaCode);

byte[] javaCode2 = Files.readAllBytes(path);