使用 ASCII 行处理 Java IO 的最快方法

发布于 2024-08-18 12:12:59 字数 268 浏览 4 评论 0原文

我正在通过 Socket 使用 ASCII 输入/输出流,速度至关重要。我听说使用正确的 Java 技术确实会带来不同。我有一本教科书说使用缓冲区是最好的方法,但也建议使用 DataInputStreamReader 进行链接。

对于输出,我使用 BufferedOutputStream 和 OutputStreamWriter ,这似乎很好。但我不确定输入流使用什么。我正在开发新线路,那么扫描仪有什么用处吗?速度至关重要,我需要尽快从网络上获取数据。

谢谢。

PH值

I'm working with an ASCII input/output stream over a Socket and speed is critical. I've heard using the right Java technique really makes a difference. I have a textbook that says using Buffers is the best way, but also suggests chaining with DataInputStreamReader.

For output I'm using a BufferedOutputStream with OutputStreamWriter which seems to be fine. But I am unsure on what to use for the input stream. I'm working on new lines, so would Scanner be of any use? Speed is critical, I need to get the data off the network as fast as possible.

Thanks.

PH

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

染墨丶若流云 2024-08-25 12:12:59

只是为了笑...

socket = new ServerSocket(2004, 10);
connection = socket.accept();
in = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String line = null;
do {
    line = br.readLine();
} while (!"done".equals(line));

使用 LOOPBACK,即仅使用本地进程在我的计算机上运行到本地主机,并且使用适当的“愚蠢”客户端。

requestSocket = new Socket("localhost", 2004);
out = requestSocket.getOutputStream();
PrintWriter pw = new PrintWriter(out);
String line =  "...1000 characters long..."; 
for (int i = 0; i < 2000000 - 1; i++) {
    pw.println(line);
}
line = "done";
pw.println(line);
pw.flush();

您会注意到这会发送 2M“1000 字符”行。这只是一个粗略的吞吐量测试。

在我的机器上,环回,我得到约 190MB/秒的传输速率。字节,而不是位。 190,000 行/秒。

我的观点是,使用骨干 Java 套接字的“简单”方式相当快。这将使任何常见的网络连接饱和(意味着网络将比 I/O 减慢速度)。

可能“足够快”。

您期望什么样的流量?

Just for laughs...

socket = new ServerSocket(2004, 10);
connection = socket.accept();
in = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String line = null;
do {
    line = br.readLine();
} while (!"done".equals(line));

With LOOPBACK, i.e. just running to localhost with local processes, on my machine, and with a suitably "stupid" client.

requestSocket = new Socket("localhost", 2004);
out = requestSocket.getOutputStream();
PrintWriter pw = new PrintWriter(out);
String line =  "...1000 characters long..."; 
for (int i = 0; i < 2000000 - 1; i++) {
    pw.println(line);
}
line = "done";
pw.println(line);
pw.flush();

You'll note that this send 2M "1000 char" lines. It's simply a crude throughput test.

On my machine, loopback, I get ~190MB/sec transfer rate. Bytes, not bits. 190,000 lines/sec.

My point is that the "unsophisticated" way using bone stock Java sockets is quite fast. This will saturate any common network connection (meaning the network will be slowing you down more than your I/O here will).

Likely "fast enough".

What kind of traffic are you expecting?

岁月流歌 2024-08-25 12:12:59

如果速度绝对重要,请考虑使用 NIO。这是针对完全相同的问题发布的代码示例。

http://lists.apple.com/archives/java- dev/2004/Apr/msg00051.html

编辑:这是另一个示例

http://www.java2s.com/Code/Java/File-Input-Output/UseNIOtoreadatextfile.htm

编辑2:我编写这个微基准测试是为了让您开始测量各种方法的性能。有些人评论说 NIO 不会执行得更快,因为您需要做更多的工作来将数据“整理”成可用的形式,这样您就可以根据您想要做的事情来验证它。当我在我的机器上运行此代码时,对于 45 兆字节的文件,NIO 代码的速度大约快 3 倍;对于 100 兆字节的文件,NIO 代码的速度大约快 5 倍。

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;

public class TestStuff {

    public static void main(final String[] args)
            throws IOException, InterruptedException {

        final String file_path = "c:\\test-nio.txt";
        readFileUsingNIO(file_path);
        readFileUsingScanner(file_path);

    }

    private static void readFileUsingScanner(final String path_to_file)
            throws FileNotFoundException {
        Scanner s = null;

        final StringBuilder builder = new StringBuilder();
        try {
            System.out.println("Starting to read the file using SCANNER");
            final long start_time = System.currentTimeMillis();
            s = new Scanner(new BufferedReader(new FileReader(path_to_file)));
            while (s.hasNext()) {
                builder.append(s.next());
            }
            System.out.println("Finished!  Read took " + (System.currentTimeMillis() - start_time) + " ms");
        }
        finally {
            if (s != null) {
                s.close();
            }
        }

    }

    private static void readFileUsingNIO(final String path_to_file)
            throws IOException {
        FileInputStream fIn = null;
        FileChannel fChan = null;
        long fSize;
        ByteBuffer mBuf;

        final StringBuilder builder = new StringBuilder();
        try {
            System.out.println("Starting to read the file using NIO");
            final long start_time = System.currentTimeMillis();
            fIn = new FileInputStream("c:\\test-nio.txt");
            fChan = fIn.getChannel();
            fSize = fChan.size();
            mBuf = ByteBuffer.allocate((int) fSize);
            fChan.read(mBuf);
            mBuf.rewind();
            for (int i = 0; i < fSize; i++) {
                //System.out.print((char) mBuf.get());
                builder.append((char) mBuf.get());
            }
            fChan.close();
            fIn.close();
            System.out.println("Finished!  Read took " + (System.currentTimeMillis() - start_time) + " ms");
        }
        catch (final IOException exc) {
            System.out.println(exc);
            System.exit(1);
        }
        finally {
            if (fChan != null) {
                fChan.close();
            }
            if (fIn != null) {
                fIn.close();
            }
        }

    }

If speed is absolutely critical, consider using NIO. Here's a code example posted for the exact same question.

http://lists.apple.com/archives/java-dev/2004/Apr/msg00051.html

EDIT: Here's another example

http://www.java2s.com/Code/Java/File-Input-Output/UseNIOtoreadatextfile.htm

EDIT 2: I wrote this microbenchmark to get you started on measuring the performance of various approaches. Some folks have commented that NIO will not perform faster because you will need to do more work to 'massage' the data into a usable form, so you can validate that based on whatever it is you're trying to do. When I ran this code on my machine, the NIO code was approximately 3 times faster with a 45 megabyte file, and 5 times faster with a 100 megabyte file.

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;

public class TestStuff {

    public static void main(final String[] args)
            throws IOException, InterruptedException {

        final String file_path = "c:\\test-nio.txt";
        readFileUsingNIO(file_path);
        readFileUsingScanner(file_path);

    }

    private static void readFileUsingScanner(final String path_to_file)
            throws FileNotFoundException {
        Scanner s = null;

        final StringBuilder builder = new StringBuilder();
        try {
            System.out.println("Starting to read the file using SCANNER");
            final long start_time = System.currentTimeMillis();
            s = new Scanner(new BufferedReader(new FileReader(path_to_file)));
            while (s.hasNext()) {
                builder.append(s.next());
            }
            System.out.println("Finished!  Read took " + (System.currentTimeMillis() - start_time) + " ms");
        }
        finally {
            if (s != null) {
                s.close();
            }
        }

    }

    private static void readFileUsingNIO(final String path_to_file)
            throws IOException {
        FileInputStream fIn = null;
        FileChannel fChan = null;
        long fSize;
        ByteBuffer mBuf;

        final StringBuilder builder = new StringBuilder();
        try {
            System.out.println("Starting to read the file using NIO");
            final long start_time = System.currentTimeMillis();
            fIn = new FileInputStream("c:\\test-nio.txt");
            fChan = fIn.getChannel();
            fSize = fChan.size();
            mBuf = ByteBuffer.allocate((int) fSize);
            fChan.read(mBuf);
            mBuf.rewind();
            for (int i = 0; i < fSize; i++) {
                //System.out.print((char) mBuf.get());
                builder.append((char) mBuf.get());
            }
            fChan.close();
            fIn.close();
            System.out.println("Finished!  Read took " + (System.currentTimeMillis() - start_time) + " ms");
        }
        catch (final IOException exc) {
            System.out.println(exc);
            System.exit(1);
        }
        finally {
            if (fChan != null) {
                fChan.close();
            }
            if (fIn != null) {
                fIn.close();
            }
        }

    }
望她远 2024-08-25 12:12:59

Scanner 用于分隔文本。您没有谈论您的数据是什么样子,所以我无法对此发表评论。

如果您只想读取每个换行符,请使用

BufferedReader r = new BufferedReader(new InputStreamReader(Socket.getInputStream()))

r.readLine()

当您得到一个空值,你就会知道你已经耗尽了流中的数据。

就速度而言,它们都只是从流中读取数据。因此,假设您不需要扫描仪的额外功能,我认为没有任何特殊的理由使用扫描仪。

A Scanner is used for delimited text. You didn't talk about what your data looks like so I can't comment on that.

If you just want to read until each newline character, use

BufferedReader r = new BufferedReader(new InputStreamReader(Socket.getInputStream()))

and

r.readLine()

When you get a null value, you will know you have exhausted the data in the stream.

As far as speed is concerned, they are both just reading data out of the stream. So assuming you don't need the extra functionality of a Scanner, I don't see any particular reason to use one.

滴情不沾 2024-08-25 12:12:59

我会用 BufferedReader 做一些事情:

Collection<String> lines = new ArrayList<String>();
BufferedReader reader = new BufferedReader( new InputStreamReader( Foo.getInputStream()));
while(reader.ready())
{
    lines.add( reader.readLine());
}

myClass.processData(lines); //Process the data after it is off the network.

根据您的情况,您可以有一个额外的线程来处理“行”中的项目,因为它被填充,但是您需要使用不同的结构来支持集合 - 可以同时使用的集合。

I would do something with a BufferedReader along the lines of:

Collection<String> lines = new ArrayList<String>();
BufferedReader reader = new BufferedReader( new InputStreamReader( Foo.getInputStream()));
while(reader.ready())
{
    lines.add( reader.readLine());
}

myClass.processData(lines); //Process the data after it is off the network.

Depending on your situation you could have an additional thread that processes the items in 'lines' as its getting filled, but then you would need to use a different structure to back the collection- one that can be used concurrently.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文