【问题标题】:Faster way of copying data in Java?在 Java 中复制数据的更快方法?
【发布时间】:2012-12-06 16:35:13
【问题描述】:

我的任务是从服务器复制数据。我正在使用BufferedInputStream 和输出流来复制数据,并且我正在逐字节进行。即使它正在运行,但复制数据需要很长时间,因为其中一些数据是 100 的 MB,所以它肯定行不通。谁能建议我逐字节复制的任何替代方案,以便我的代码可以复制几百 MB 的文件。 缓冲区为 2048。

我的代码如下所示:

static void copyFiles(SmbFile[] files, String parent) throws IOException {

  SmbFileInputStream input = null;
  FileOutputStream output = null;
  BufferedInputStream buf_input = null;
  try {
    for (SmbFile f : files) {
      System.out.println("Working on files :" + f.getName());
      if (f.isDirectory()) {

        File folderToBeCreated = new File(parent+f.getName());
        if (!folderToBeCreated.exists()) {
          folderToBeCreated.mkdir();
          System.out.println("Folder name " + parent
                + f.getName() + "has been created");
        } else {
          System.out.println("exists");

        }

        copyFiles(f.listFiles(), parent +  f.getName());
      } else {

        input = (SmbFileInputStream) f.getInputStream();

        buf_input = new BufferedInputStream(input, BUFFER);

        File t = new File(parent + f.getName());
        if (!t.exists()) {
          t.createNewFile();
        }
        output = new FileOutputStream(t);

        int c;

        int count;
        byte data[] = new byte[BUFFER];

        while ((count = buf_input.read(data, 0, BUFFER)) != -1) {
          output.write(data, 0, count);
        }
      }
    }
  } catch (IOException e) {
    e.printStackTrace();

  } finally {
    if (input != null) {
      input.close();
    }
    if (output != null) {
      output.close();
    }
  }
}

【问题讨论】:

  • 现在您已经展示了代码,您不是逐字节读取,除非 BUFFER 为 1。(您的异常处理可能需要做一些工作,由方式...这几乎不是一个合适的 catch 块。)
  • @JonSkeet 你的意思是我应该为每个文件添加try catch,这样即使一个文件失败,其他文件也不会受到影响
  • @JonSkeet 你能告诉我关于 try,catch 块我应该怎么做非常感谢
  • @Batman:如果出现 IO 故障,您想要怎么办?你真的要继续吗?你已经声明你的方法可以抛出 IOException,那么为什么要在你的方法中捕获它呢?
  • @JonSkeet 实际上是在关闭流时发生一些错误

标签: java performance file-io copy bufferedinputstream


【解决方案1】:

这里有一个link to an excellent post 解释如何使用nio 频道来制作流的副本。它引入了一个帮助方法ChannelTools.fastChannelCopy,让您可以像这样复制流:

final InputStream input = new FileInputStream(inputFile);
final OutputStream output = new FileOutputStream(outputFile);
final ReadableByteChannel inputChannel = Channels.newChannel(input);
final WriteableByteChannel outputChannel = Channels.newChannel(output);
ChannelTools.fastChannelCopy(inputChannel, outputChannel);
inputChannel.close();
outputChannel.close()

【讨论】:

  • @Batman 可能,因为Channels.newChannel 采用InputStream,而SmbFileInputStreamInputStream。我一定会试一试的。
  • 是的,也为 SmbFile 工作过。使用旧方法需要 372 秒的传输,现在需要 286 秒 :)
【解决方案2】:

因为您使用的是BufferedInputStream,所以您不是逐字节读取,而是缓冲区的大小。您可以尝试增加缓冲区大小。

【讨论】:

    【解决方案3】:

    逐字节读取/写入肯定会很慢,即使实际读取/写入是由缓冲区大小的块完成的。加速它的一种方法是按块读取/写入。看看BufferedInputStreamread(byte[] b, int off, int len) 方法。但是,它可能不会给您带来足够的改进。

    使用nio包(新IO)使用nio通道复制数据会更好。请查看nio documentation 了解更多信息。

    【讨论】:

      【解决方案4】:

      我建议使用org.apache.commons.io 中的FileUtils。它有足够的实用方法来执行文件操作。

      org.apache.commons.io.FileUtils API Here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-11
        • 2011-03-10
        • 1970-01-01
        • 2011-07-03
        • 2020-08-18
        • 2018-06-09
        • 1970-01-01
        • 2020-10-12
        相关资源
        最近更新 更多