Java CharBuffer 与 char[]

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/294382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:40:42  来源:igfitidea点击:

CharBuffer vs. char[]

javaiobuffer

提问by Chris Conway

Is there any reason to prefer a CharBufferto a char[]in the following:

是否有任何理由更喜欢以下中的aCharBuffer到 a char[]

CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
while( in.read(buf) >= 0 ) {
  out.append( buf.flip() );
  buf.clear();
}

vs.

对比

char[] buf = new char[DEFAULT_BUFFER_SIZE];
int n;
while( (n = in.read(buf)) >= 0 ) {
  out.write( buf, 0, n );
}

(where inis a Readerand outin a Writer)?

(在ina中的aReaderout在哪里Writer)?

采纳答案by erickson

No, there's really no reason to prefer a CharBufferin this case.

不,CharBuffer在这种情况下真的没有理由更喜欢 a 。

In general, though, CharBuffer(and ByteBuffer) can really simplify APIs and encourage correct processing. If you were designing a public API, it's definitely worth considering a buffer-oriented API.

但总的来说,CharBuffer(和ByteBuffer)确实可以简化 API 并鼓励正确处理。如果您正在设计一个公共 API,那么绝对值得考虑一个面向缓冲区的 API。

回答by Bill Michell

If this is the only thing you're doing with the buffer, then the array is probably the better choice in this instance.

如果这是您对缓冲区所做的唯一事情,那么在这种情况下,数组可能是更好的选择。

CharBuffer has lots of extra chrome on it, but none of it is relevant in this case - and will only slow things down a fraction.

CharBuffer 上有很多额外的 chrome,但在这种情况下没有一个是相关的 - 并且只会减慢一小部分。

You can always refactor later if you need to make things more complicated.

如果您需要使事情变得更复杂,您可以随时进行重构。

回答by Michael Rutherfurd

The CharBuffer version is slightly less complicated (one less variable), encapsulates buffer size handling and makes use of a standard API. Generally I would prefer this.

CharBuffer 版本稍微不那么复杂(少一个变量),封装了缓冲区大小处理并使用了标准 API。一般来说,我更喜欢这个。

However there is still one good reason to prefer the array version, in some cases at least. CharBuffer was only introduced in Java 1.4 so if you are deploying to an earlier version you can'tuse Charbuffer (unless you role-your-own/use a backport).

然而,至少在某些情况下,仍然有一个很好的理由更喜欢数组版本。CharBuffer 仅在 Java 1.4 中引入,因此如果您要部署到早期版本,则不能使用 Charbuffer(除非您扮演自己的角色/使用反向移植)。

P.S If you use a backport remember to remove it once you catch up to the version containing the "real"version of the backported code.

PS 如果您使用向后移植,请记住在赶上包含向后移植代码的“真实”版本的版本后将其删除。

回答by Eric

I think that CharBuffer and ByteBuffer (as well as any other xBuffer) were meant for reusability so you can buf.clear() them instead of going through reallocation every time

我认为 CharBuffer 和 ByteBuffer(以及任何其他 xBuffer)是为了可重用性,因此您可以 buf.clear() 它们而不是每次都进行重新分配

If you don't reuse them, you're not using their full potential and it will add extra overhead. However if you're planning on scaling this function this might be a good idea to keep them there

如果您不重用它们,您就没有充分利用它们的潜力,并且会增加额外的开销。但是,如果您计划扩展此功能,那么将它们保留在那里可能是个好主意

回答by Ron Tuffin

I wanted to mini-benchmark this comparison.

我想对这种比较进行小型基准测试。

Below is the class I have written.

下面是我写的类。

The thing is I can't believe that the CharBuffer performed so badly. What have I got wrong?

问题是我无法相信 CharBuffer 的表现如此糟糕。我做错了什么?

EDIT: Since the 11th comment below I have edited the code and the output time, better performance all round but still a significant difference in times. I also tried out2.append((CharBuffer)buff.flip()) option mentioned in the comments but it was much slower than the write option used in the code below.

编辑:自从下面的第 11 条评论以来,我已经编辑了代码和输出时间,全面提高了性能,但在时间上仍然存在显着差异。我还尝试了注释中提到的 out2.append((CharBuffer)buff.flip()) 选项,但它比下面代码中使用的 write 选项慢得多。

Results: (time in ms)
char[] : 3411
CharBuffer: 5653

结果:(时间以毫秒为单位)
char[]:3411
CharBuffer:5653

public class CharBufferScratchBox
{
    public static void main(String[] args) throws Exception
    {
        // Some Setup Stuff
        String smallString =
                "1111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000";

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 1000; i++)
        {
            stringBuilder.append(smallString);
        }
        String string = stringBuilder.toString();
        int DEFAULT_BUFFER_SIZE = 1000;
        int ITTERATIONS = 10000;

        // char[]
        StringReader in1 = null;
        StringWriter out1 = null;
        Date start = new Date();
        for (int i = 0; i < ITTERATIONS; i++)
        {
            in1 = new StringReader(string);
            out1 = new StringWriter(string.length());

            char[] buf = new char[DEFAULT_BUFFER_SIZE];
            int n;
            while ((n = in1.read(buf)) >= 0)
            {
                out1.write(
                        buf,
                        0,
                        n);
            }
        }
        Date done = new Date();
        System.out.println("char[]    : " + (done.getTime() - start.getTime()));

        // CharBuffer
        StringReader in2 = null;
        StringWriter out2 = null;
        start = new Date();
        CharBuffer buff = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
        for (int i = 0; i < ITTERATIONS; i++)
        {
            in2 = new StringReader(string);
            out2 = new StringWriter(string.length());
            int n;
            while ((n = in2.read(buff)) >= 0)
            {
                out2.write(
                        buff.array(),
                        0,
                        n);
                buff.clear();
            }
        }
        done = new Date();
        System.out.println("CharBuffer: " + (done.getTime() - start.getTime()));
    }
}

回答by James Schek

The difference, in practice, is actually <10%, not 30% as others are reporting.

实际上,差异实际上小于 10%,而不是其他人报告的 30%。

To read and write a 5MB file 24 times, my numbers taken using a Profiler. They were on average:

为了读取和写入 5MB 文件 24 次,我使用 Profiler 获取了我的数字。他们平均:

char[] = 4139 ms
CharBuffer = 4466 ms
ByteBuffer = 938 (direct) ms

Individual tests a couple times favored CharBuffer.

个别测试有几次偏爱 CharBuffer。

I also tried replacing the File-based IO with In-Memory IO and the performance was similar. If you are trying to transfer from one native stream to another, then you are better off using a "direct" ByteBuffer.

我还尝试用内存 IO 替换基于文件的 IO,性能相似。如果您尝试从一个本机流传输到另一个流,那么最好使用“直接”ByteBuffer。

With less than 10% performance difference, in practice, I would favor the CharBuffer. It's syntax is clearer, there's less extraneous variables, and you can do more direct manipulation on it (i.e. anything that asks for a CharSequence).

由于性能差异不到 10%,在实践中,我更喜欢 CharBuffer。它的语法更清晰,无关变量更少,您可以对其进行更直接的操作(即任何需要 CharSequence 的操作)。

Benchmark is below... it is slightly wrong as the BufferedReader is allocated inside the test-method rather than outside... however, the example below allows you to isolate the IO time and eliminate factors like a string or byte stream resizing its internal memory buffer, etc.

基准低于......它有点错误,因为 BufferedReader 是在测试方法内部而不是外部分配的......但是,下面的示例允许您隔离 IO 时间并消除诸如调整其内部大小的字符串或字节流之类的因素内存缓冲区等

public static void main(String[] args) throws Exception {
    File f = getBytes(5000000);
    System.out.println(f.getAbsolutePath());
    try {
        System.gc();
        List<Main> impls = new java.util.ArrayList<Main>();
        impls.add(new CharArrayImpl());
        //impls.add(new CharArrayNoBuffImpl());
        impls.add(new CharBufferImpl());
        //impls.add(new CharBufferNoBuffImpl());
        impls.add(new ByteBufferDirectImpl());
        //impls.add(new CharBufferDirectImpl());
        for (int i = 0; i < 25; i++) {
            for (Main impl : impls) {
                test(f, impl);
            }
            System.out.println("-----");
            if(i==0)
                continue; //reset profiler
        }
        System.gc();
        System.out.println("Finished");
        return;
    } finally {
        f.delete();
    }
}
static int BUFFER_SIZE = 1000;

static File getBytes(int size) throws IOException {
    File f = File.createTempFile("input", ".txt");
    FileWriter writer = new FileWriter(f);
    Random r = new Random();
    for (int i = 0; i < size; i++) {
        writer.write(Integer.toString(5));
    }
    writer.close();
    return f;
}

static void test(File f, Main impl) throws IOException {
    InputStream in = new FileInputStream(f);
    File fout = File.createTempFile("output", ".txt");
    try {
        OutputStream out = new FileOutputStream(fout, false);
        try {
            long start = System.currentTimeMillis();
            impl.runTest(in, out);
            long end = System.currentTimeMillis();
            System.out.println(impl.getClass().getName() + " = " + (end - start) + "ms");
        } finally {
            out.close();
        }
    } finally {
        fout.delete();
        in.close();
    }
}

public abstract void runTest(InputStream ins, OutputStream outs) throws IOException;

public static class CharArrayImpl extends Main {

    char[] buff = new char[BUFFER_SIZE];

    public void runTest(InputStream ins, OutputStream outs) throws IOException {
        Reader in = new BufferedReader(new InputStreamReader(ins));
        Writer out = new BufferedWriter(new OutputStreamWriter(outs));
        int n;
        while ((n = in.read(buff)) >= 0) {
            out.write(buff, 0, n);
        }
    }
}

public static class CharBufferImpl extends Main {

    CharBuffer buff = CharBuffer.allocate(BUFFER_SIZE);

    public void runTest(InputStream ins, OutputStream outs) throws IOException {
        Reader in = new BufferedReader(new InputStreamReader(ins));
        Writer out = new BufferedWriter(new OutputStreamWriter(outs));
        int n;
        while ((n = in.read(buff)) >= 0) {
            buff.flip();
            out.append(buff);
            buff.clear();
        }
    }
}

public static class ByteBufferDirectImpl extends Main {

    ByteBuffer buff = ByteBuffer.allocateDirect(BUFFER_SIZE * 2);

    public void runTest(InputStream ins, OutputStream outs) throws IOException {
        ReadableByteChannel in = Channels.newChannel(ins);
        WritableByteChannel out = Channels.newChannel(outs);
        int n;
        while ((n = in.read(buff)) >= 0) {
            buff.flip();
            out.write(buff);
            buff.clear();
        }
    }
}

回答by akuhn

You should avoid CharBufferin recent Java versions, there is a bug in #subsequence(). You cannot get a subsequence from the second half of the buffer since the implementation confuses capacityand remaining. I observed the bug in java 6-0-11 and 6-0-12.

你应该避免CharBuffer在最近的 Java 版本中,在#subsequence(). 由于实现混淆了capacity和,因此您无法从缓冲区的后半部分获得子序列remaining。我观察到 java 6-0-11 和 6-0-12 中的错误。