从输入流的末尾删除N个字节

时间:2016-08-10 15:10:25

标签: java byte inputstream httpurlconnection

我的目标是从另一个文件中删除文件的内容,我可以通过HttpURLConnection访问这些文件。

我的想法是从第一个文件中获取内容长度,让我们调用N这个内容长度。并从第二个输入流(file2)中删除N个字节。

HttpURLConnection connection1 = (HttpURLConnection) url1.openConnection();
HttpURLConnection connection2 = (HttpURLConnection) url2.openConnection();

String contentLength1 = connection1.getHeaderFields().get("Content-Length").get(0);
String contentLength2 = connection2.getHeaderFields().get("Content-Length").get(0);
InputStream is = connection2.getInputStream();

编辑:

我找到了一种方法,我想知道是否有更好的方法。

ByteArrayOutputStream into = new ByteArrayOutputStream();
byte[] buf = new byte[4096];

for (int n; 0 < (n = is.read(buf));) {
    into.write(buf, 0, n);
}
into.close();

byte[] data = into.toByteArray();
int length1 = Integer.parseInt(contentLength1);
int length2 = Integer.parseInt(contentLength2);
byte[] newData = new byte[length2-length1];

System.arraycopy(data, 0, newData, 0, newData.length);
ByteArrayInputStream newStream = new ByteArrayInputStream(newData);

2 个答案:

答案 0 :(得分:0)

将InputStream包装在一个只读取所需长度的类中。

class TruncatedInputStream extends InputStream {

    private final InputStream in;
    private final long maxLength;
    private long position;

    TruncatedInputStream(InputStream in, long maxLength) ... {
        this.in = in;
        this.maxLength = maxLength;
    }

    @Override
    int read() ... {
        if (position >= maxLength) {
            return -1;
        }
        int ch = in.read();
        if (ch != -1) {
            ++position;
        }
        return -1;
    }
}

介意跳过,重置。使用BufferedInputStream是不可取的。

它实际上有点打字,但提供了一个只有一个责任的可靠工具。

答案 1 :(得分:0)

我尝试了existing answer,但是它对我不起作用-特别是我看不到read方法如何返回除-1之外的任何值。

我用以下内容扩展了它:

/**
 * Truncates a {@link java.io.InputStream} to a specified number of bytes. <br>
 * <br>
 * Based on <a href="https://stackoverflow.com/a/38891920">this implementation</a>. <br>
 * <br>
 * <a href="https://stackoverflow.com/a/52149547">Source</a>.
 */
public class TruncatedInputStream extends InputStream
{
    private final InputStream inputStream;
    private final long maxLengthInBytes;
    private long position;

    /** @see TruncatedInputStream */
    public TruncatedInputStream(final InputStream inputStream, final long maxLengthInBytes)
    {
        this.inputStream = inputStream;
        this.maxLengthInBytes = maxLengthInBytes;
    }

    @Override
    public int read() throws IOException
    {
        return position++ < maxLengthInBytes ? inputStream.read() : -1;
    }
}

此外,我写了一个单元测试:

public class TruncatedInputStreamTest
{
    @Test
    public void testTruncatedInputStream() throws IOException
    {
        byte[] input = new byte[] {};
        doTest(input, new byte[] {}, 1);
        doTest(input, new byte[] {}, 0);

        input = new byte[] {0};
        doTest(input, new byte[] {0}, 1);
        doTest(input, new byte[] {}, 0);

        input = new byte[] {0, 1};
        doTest(input, new byte[] {0, 1}, 3);
        doTest(input, new byte[] {0, 1}, 2);
        doTest(input, new byte[] {0}, 1);
        doTest(input, new byte[] {}, 0);

        input = new byte[] {0, 1, 2};
        doTest(input, new byte[] {0, 1, 2}, 3);
        doTest(input, new byte[] {0, 1}, 2);
        doTest(input, new byte[] {0}, 1);
        doTest(input, new byte[] {}, 0);
    }

    private void doTest(final byte[] input, final byte[] expectedOutput, final long length) throws IOException
    {
        try (PipedInputStream pipedInputStream = new PipedInputStream(); InputStream truncatedInputStream = new TruncatedInputStream(pipedInputStream, length))
        {
            try (OutputStream outputStream = new PipedOutputStream(pipedInputStream))
            {
                IOUtils.write(input, outputStream);
            }

            final byte[] actualOutput = IOUtils.toByteArray(truncatedInputStream);

            assertArrayEquals(Arrays.toString(actualOutput), expectedOutput, actualOutput);
        }
    }
}