简体   繁体   English

跟踪复制文件的进度

[英]track progress of copying files

I am trying to track the progress of a compression progress. 我试图跟踪压缩进度的进度。 ATM I am doing it like this: ATM我这样做:

public static void compressGzipTest(final OutputStream os, final File source) throws CompressorException,
            IOException
    {
        final CountingInputStream cis = new CountingInputStream(new FileInputStream(source));
        final GzipCompressorOutputStream gzipOut = (GzipCompressorOutputStream) new CompressorStreamFactory()
                .createCompressorOutputStream(CompressorStreamFactory.GZIP,os);

        new Thread() {
            public void run()
            {
                try
                {
                    long fileSize = source.length();

                    while (fileSize > cis.getBytesRead())
                    {
                        Thread.sleep(1000);
                        System.out.println(cis.getBytesRead() / (fileSize / 100.0));
                    }
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
            }
        }.start();

        IOUtils.copy(cis,gzipOut);
    }

This works fine, but I need the thread, which is giving feedback about the progress not to be implemented in this method, but when calling it (in order to create something like a progressbar on an android device). 这工作正常,但我需要线程,它提供有关在此方法中不实现的进度的反馈,但在调用它时(为了在Android设备上创建类似于进度条的东西)。 So this is more like an architectural issue. 所以这更像是一个架构问题。 Any ideas, on how to solve that? 关于如何解决的任何想法?

I meanwhile solved it via overwriting the IOUtils.copy() by adding an interface as parameter: 我同时通过添加接口作为参数来覆盖IOUtils.copy()来解决它:

public static long copy(final InputStream input, final OutputStream output, int buffersize,
        ProgressListener listener) throws IOException
{
    final byte[] buffer = new byte[buffersize];
    int n = 0;
    long count = 0;
    while (-1 != (n = input.read(buffer)))
    {
        output.write(buffer,0,n);
        count += n;
        listener.onProgress(n);
    }
    return count;
}

which is then called by something like this 然后通过这样的东西调用

copy(input, output, 4096, new ProgressListener() {

                long totalCounter = 0;

                DecimalFormat f = new DecimalFormat("#0.00");

                @Override
                public void onProgress(long bytesRead)
                {
                    totalCounter += bytesRead;
                    System.out.println(f.format(totalCounter / (fileSize / 100.0)));
                }
            });

The only thing, i am challenged by now, is to limit the output on the console not for each byte[4096] but for let's say each two megabyte. 我现在面临的唯一挑战是限制控制台上的输出而不是每个字节[4096],但是让我们说每两兆字节。 I tried something like this: 我试过这样的事情:

while (-1 != (n = input.read(buffer)))
    {
        output.write(buffer,0,n);
        count += n;
        while(n % 2097152 == 0)
        {
          listener.onProgress(n);
        }
    }
    return count;

But that does not give me any output at all 但这根本不给我任何输出

You should implement the copy mechanism in AsyncTask . 您应该在AsyncTask中实现复制机制。 It runs on a background thread, but you can post progress with the publishProgress method. 它在后台线程上运行,但您可以使用publishProgress方法发布进度。 After this you can handle these events on the UI thread with the onProgressUpdate callback of the AsyncTask . 在此之后,您可以使用AsyncTaskonProgressUpdate回调在UI线程上处理这些事件。

        @Override
        protected void onProgressUpdate(final Double... values) {
            super.onProgressUpdate(values);
            //...
        }

EDIT: Example: 编辑:示例:

        final byte[] buf = new byte[1024];
        try {
            int bufferSize;
            final int size = inputStream.available();

            long alreadyCopied = 0;
            while ((bufferSize = inputStream.read(buf)) > 0 && canRun.get()) {
                alreadyCopied += bufferSize;
                outputStream.write(buf, 0, bufferSize);
                publishProgress(1.0d * alreadyCopied / size);
            }
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.flush();
                outputStream.getFD().sync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

I have a very similar solution to the one proposed by JohnPlata . 我对JohnPlata提出的解决方案有一个非常类似的解决方案。 I took the copy Method from IOUtils and added two parameters: the original filesize of the file to be copied from and a listener for updating the progress. 我从IOUtilscopy方法并添加了两个参数:要复制的文件的原始文件大小和用于更新进度的监听器。 My copy happens during unpacking a .gz file and since the unpacked files are roughly 3 times bigger than the packed files I estimate the end result file size (hence the line copy(in, out, inputFile.length()*3, progressListener); ). 我的副本在解压缩.gz文件时发生,因为解压缩的文件大约是打包文件的3倍,我估计最终结果文件大小(因此行copy(in, out, inputFile.length()*3, progressListener); )。 The whole thing is Android-based, so the Listener updates a notification with the progress. 整个过程都是基于Android的,因此Listener会根据进度更新通知。

public static File unGzip(final File inputFile, final File outputDir, ProgressListener progressListener)
        throws FileNotFoundException, IOException {
    final File outputFile = new File(outputDir, inputFile.getName()
            .substring(0, inputFile.getName().length() - 3));
    final GZIPInputStream in = new GZIPInputStream(new FileInputStream(inputFile));
    final FileOutputStream out = new FileOutputStream(outputFile);
    copy(in, out, inputFile.length()*3, progressListener);
    in.close();
    out.close();
    return outputFile;
}

public static long copy(InputStream input, OutputStream output, long inputfilesize,
                        ProgressListener progressListener)
        throws IOException {
    byte[] buffer = new byte[8024];
    boolean n = false;
    long percent = 0;
    long count;
    int n1;
    for(count = 0L; -1 != (n1 = input.read(buffer)); count += (long)n1) {
        output.write(buffer, 0, n1);
        if ((count*100)/inputfilesize > percent) {
            percent = (count*100)/inputfilesize;
            progressListener.onProgressUpdate((int)percent);
        }
    }
    return count;
}

The code of the class where all of this is called looks like this: 调用所有这些的类的代码如下所示:

File ungzippedFile = Util.unGzip(movedFile, offlineDataDirFile, new ProgressListener() {
    @Override
    public void onProgressUpdate(int percentage) {
        notificationBuilder.setProgress(100, percentage, false);
        notificationManagerCompat.notify(1, notificationBuilder.build());
    }
});

This class also contains the interface: 该类还包含接口:

public interface ProgressListener {
    void onProgressUpdate(int percentage);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM