InputStream 或 Reader。具有相同逻辑的方法

InputStream or Reader. Method with same logic

我需要实现相同的逻辑:比较文件使用 InputStream 以二进制形式进行比较,使用 Reader 以 unicode 进行比较。 我能以某种方式制作一个采用 InputStreamReader 的方法,并与采用参数的 read() 方法执行相同的逻辑吗?

找不到这种情况的通配符,因为据我所知,InputStreamReader 没有交互层次结构。

我需要一个采用 BufferedInputStreamBufferedReader 的方法。

您可以使用重载创建两个方法,这意味着每个方法都采用您想要支持的输入之一。

定义一个具有您需要从这两个方法访问的功能的接口,然后编写实现该接口的包装器 类(这些可以是相应方法中的匿名内部 类)。

将包装的输入传递给在接口上工作的内部私有处理方法,而不关心它可能包装的是什么。

这可以扩展为支持任意数量的不同类型的传入对象(只要可以包装它们),只需为每个对象添加一个新方法和一个新包装器即可。

一些或多或少通用的方法,您可以根据需要进行扩展。这个想法是将原始流通过管道传输到另一个流,以便在当前线程中读取原始流时由另一个线程读取。所以这里的 TeeInputStream 用于包装原始流并将流中的数据副本发送到 PipeOutputStream。反过来,PipeOutputStream 正在被 PipeInputStream 读取,即单独线程中的 运行。流的内容是 "hashed" 通过 MD5 进行比较,当两个流都被完全读取时,但是您可以使用任何您想要比较字节数据的方法(差异等)。

这有点冗长,但如果您需要将流提供给 XML reader 并同时计算流的 CRC 或 MD5 校验和,则效果很好无需从流中读取两次。

    import org.apache.commons.io.input.TeeInputStream;

    import java.io.*;
    import java.security.MessageDigest;
    import java.util.Arrays;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;

    public class Test1 {

        private static final ExecutorService executor = Executors.newFixedThreadPool(2);

        public static boolean compareStreams(InputStream is1, InputStream is2) throws Exception {
            // create pipe that will copy data from is1 to pipe accessible by pis1
            final PipedOutputStream pos1 = new PipedOutputStream();
            final PipedInputStream pis1 = new PipedInputStream(pos1, 1024);
            final TeeInputStream tee1 = new TeeInputStream(is1, pos1, true);

            // create pipe that will copy data from is2 to pipe accessible by pis2
            final PipedOutputStream pos2 = new PipedOutputStream();
            final PipedInputStream pis2 = new PipedInputStream(pos2, 1024);
            final TeeInputStream tee2 = new TeeInputStream(is2, pos2, true);

            class Comparator implements Runnable {
                private final InputStream is;
                final MessageDigest md = MessageDigest.getInstance("MD5");

                public Comparator(InputStream is) throws Exception {
                    this.is = is;
                }

                @Override
                public void run() {
                    byte[] arr = new byte[1024];
                    int read = 0;
                    try {
                        while ((read = is.read(arr)) >= 0) {
                            md.update(arr, 0, read);
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }

            Comparator comparatorIs1 = new Comparator(pis1);
            Future<?> f1 = executor.submit(comparatorIs1);
            Comparator comparatorIs2 = new Comparator(pis2);
            Future<?> f2 = executor.submit(comparatorIs2);

            Reader r1 = new InputStreamReader(is1);
            Reader r2 = new InputStreamReader(is2);

            char[] c1 = new char[1024];
            char[] c2 = new char[1024];

            int read1 = 0;
            int read2 = 0;

            boolean supposeEquals = true;

            while (supposeEquals) {
                read1 = r1.read(c1);
                read2 = r2.read(c2);
                if (read1 != read2 || (read1 < 0 && read2 < 0)) {
                    break;
                }
                for (int i = 0; i < read1; i++) {
                    if (c1[i] != c2[i]) {
                        supposeEquals = false;
                        break;
                    }
                }
            }

            f1.cancel(true);
            f2.cancel(true);

            return read1 == read2 && supposeEquals && Arrays.equals(comparatorIs1.md.digest(), comparatorIs2.md.digest());
        }

        public static void main(String[] args) throws Exception {
            System.out.println("Comparison result : " + compareStreams(new ByteArrayInputStream("test string here".getBytes()), new ByteArrayInputStream("test string here".getBytes())));
            System.out.println("Comparison result : " + compareStreams(new ByteArrayInputStream("test string test".getBytes()), new ByteArrayInputStream("test string here".getBytes())));
            System.out.println("Comparison result : " + compareStreams(new ByteArrayInputStream("test".getBytes()), new ByteArrayInputStream("test string here".getBytes())));
        }

    }