高效的数据传输机制

时间:2014-01-04 00:40:38

标签: java performance file-io data-transfer

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

在浏览Java 7 API规范后,我注意到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();
}

然后我决定用以下测试对它进行测试(第一个版本没有使用临时字节数组,并且正如预期的那样比transmit()方法更差):

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()方法为192毫秒,“直接方法”为8毫秒),这意味着“直接方法”是与transmit()方法相比效率很高。

但是,由于此类的目的是从在线源下载文件,我创建了一个40 Mb文件,我上传到个人云(并从类似于上面的方法)得到以下结果:< / p>

Transmitter method: 126478 milliseconds
Direct method (8192 bytes): 134105 milliseconds

这意味着来自在线资源的transmit()方法效率更高。

我想知道这些结果是否准确(因为这些方法是系统相关的,我说我正在运行Ubuntu 13.10),如果它们是,我怎样才能找到一种方法来优化transmit()方法到一般情况。

如果有更高效的替代方法,我也会感激,如果有人说出来的话(不需要代码,只是对方法的解释,也许是为什么它更有效)。

1 个答案:

答案 0 :(得分:2)

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

另外,谈到不好的做法,你不应该使用java的Date,而是使用更加理智的Date功能,比如Joda's DateTime,你不应该打开/关闭自己的流,而是使用库这样做或者使用Java 7的Closabletry-with-resources语句。

修改 您在示例中执行的另一个不好的做法是使用java.util.Date来获取当前时间。这在两个层面上是错误的:代码可读性和线程安全性。

对于代码可读性部分:您要做的是'give me the current time',您可以通过System.getCurrentTimeMillis()明确地执行此操作。你实际在做的是:

  

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

。当你可以轻松地避免它时创建两个额外的对象并不是什么大问题,但是因为存在一种给你当前时间的方法,而且效率更高,你应该使用它,否则你就会开发不好的做法。

对于线程安全部分,您​​可以阅读: How to make Java.util.Date thread-safe

使用java.util.Date的代码本质上容易出错,你不应该使用它。在这个例子中,这似乎不是什么大不了的事,但如果你是一名软件工程师,那么细节就很重要。此外,您不应该编写自己的数据传输方法,除非您知道现有的方法有什么问题,并且您想要改进或者您正在为家庭作业或学习目的这样做。