Java 高效的数据传输机制

Java 高效的数据传输机制,java,performance,file-io,data-transfer,Java,Performance,File Io,Data Transfer,我正在开发一个Java类来将数据从任何输入流传输到任何输出流(主要用于在线,但有更广泛的实用程序) 在浏览了Java7API规范之后,我注意到FileChannel类中有两种方法:transferFrom(…)和transferTo 我围绕这些方法开发了我的类,并创建了以下transmit()方法: public void transmit() throws IOException { File tmp = File.createTempFile("transmit", ".tmp");

我正在开发一个Java类来将数据从任何输入流传输到任何输出流(主要用于在线,但有更广泛的实用程序)

在浏览了Java7API规范之后,我注意到
FileChannel
类中有两种方法:
transferFrom(…)
transferTo

我围绕这些方法开发了我的类,并创建了以下
transmit()
方法:

public void transmit() throws IOException {
    File tmp = File.createTempFile("transmit", ".tmp");
    RandomAccessFile raf = new RandomAccessFile(tmp, "rw");
    FileChannel fc = raf.getChannel();
    fc.force(true);
    fc.transferFrom(Channels.newChannel(src), 0, Long.MAX_VALUE);
    raf.seek(0);
    fc.transferTo(0, Long.MAX_VALUE, Channels.newChannel(dst));
    raf.close();
}
public static void main(String[] args) throws IOException {
    File from = File.createTempFile("source", ".tmp");
    File to = File.createTempFile("destination", ".tmp");

    FileOutputStream tmp = new FileOutputStream(from);

    for (int i = 0; i < (1 << 20); i++) {
        tmp.write(0);
    }

    tmp.close();

    FileInputStream fin = new FileInputStream(from);
    FileOutputStream fout = new FileOutputStream(to);

    DataTransmitter dt = new DataTransmitter(fin, fout);

    long time_1 = new Date().getTime();
    dt.transmit();
    time_1 = new Date().getTime() - time_1;

    fin.close();
    fout.close();

    to.delete();

    fin = new FileInputStream(from);
    fout = new FileOutputStream(to);


    int len;
    byte[] b = new byte[8192];
    long time_2 = new Date().getTime();
    while ((len = fin.read(b)) >= 0) {
        fout.write(b, 0, len);
    }
    time_2 = new Date().getTime() - time_2;

    fin.close();
    fout.close();

    System.out.format("Transmitter method: %s milliseconds%n", time_1);
    System.out.format("Direct method: %s milliseconds%n", time_2);
}
然后我决定用下面的测试对它进行测试(第一个版本没有使用临时字节数组,正如预期的那样,比
transmit()
方法更糟糕):

这意味着
transmit()
方法从在线来源获得的效率更高

我想知道这些结果是否准确(因为这些方法依赖于系统,我声明我正在运行Ubuntu 13.10),如果准确,我如何找到一种方法来优化
transmit()
方法以适应一般情况


如果有更有效的替代方法,我也希望有人能说明它们(不需要代码,只需要解释方法,也许还有它更有效的原因)。

不要编写自己的数据传输代码,除非你有非常具体的理由这样做。有许多数据传输java库:、的某些部分等。您不应该重新发明轮子,除非您想为学校项目这样做,或者您看到现有解决方案中存在需要改进的弱点

另外,说到不好的实践,您不应该使用java的日期,而是更合理的日期功能,例如,您不应该打开/关闭自己的流,而是使用一个为您执行此操作的库,或者使用java 7的and语句

编辑: 在示例中,另一个糟糕的做法是使用java.util.Date获取当前时间。这在两个层面上是错误的:代码可读性和线程安全性

对于代码可读性部分:您试图做的是
“给我当前时间”
,您可以通过
System.getCurrentTimeMillis()
清楚地做到这一点。您实际正在做的是:

'分配一个半弃用对象,不指定时区或区域设置 (可能会从第一次呼叫变为第二次呼叫),不要 线程安全,并给我它的当前时间,以便我可以使用它作为我的 当前时间'

。在可以轻松避免的情况下创建两个额外的对象并不是什么大问题,但是由于存在一种为您提供当前时间的方法,而且这种方法更有效,因此您应该使用它,否则您将产生不良做法

对于螺纹安全部分,您可以阅读以下内容:


仅使用java.util.Date编写代码本身就容易出错,您不应该使用它。在本例中,这似乎不是什么大不了的事情,但如果您正在将自己发展为软件工程师,那么细节是很重要的。此外,除非您知道现有方法有什么问题,并且希望改进,或者您这样做是为了家庭作业或研究。

为什么
Date
完全不适合OP的用例?无论哪种方式,Joda Time都是
java.util.Calendar
的替代品,而不是
Date
的替代品。(主要是围绕
long
的强类型包装)@millimoose所有使用日期的代码本质上都是笨拙和错误的。此外,在本例中,OP使用Date作为获取System.getCurrentTimeMillis()的奇怪方式,并分配其他对象,这是一种不好的做法,除了不可读之外。如果要获取当前时间,请获取当前时间,不要创建一个模糊的不推荐对象并将其从中删除。此外,他的代码使用日期不是线程安全的:。他们没有使用线程、共享
日期或对其进行变异。线程安全是您正在构建的一个稻草人——您可能会在所有地方使用可变(如ORMs所需)实体类,而不会说它们“天生容易出错”。“不可读”是主观的,我认为这是介于
newdate()
System.getCurrentTimeMillis()
之间的冲突。分配额外的对象是一种非常荒谬的做法,在任何Java程序中,如果没有特别编码来避免这种情况,那么您将分配各种随机的非常短暂的垃圾。
Date
本身并没有被弃用,它的日历计算功能就是。即,在抽象时间戳和人类可读的日期和时间之间转换的方法。它们被弃用,因为它们并不真正支持国际化或时区——API似乎只支持当前系统的语言环境和TZ,JDK没有在
Date
类中修复它们,而是采用了ICU的
日历组件。(不管是好是坏。Joda Time背后的一个重要动机是
日历的API太疯狂了。)@millimoose,除了构造函数之外,几乎所有的日期功能都被弃用了。拜托,别傻了。具有日期的代码不能是生产代码。Date的getTime()方法上带有“see”注释的建议方法正是System.getCurrentTimeMillis()。这是OP应该用来获取时间的东西。这类开放式的“有什么建议吗?”问题可能更适合我。
Transmitter method: 126478 milliseconds
Direct method (8192 bytes): 134105 milliseconds