我正在尝试跟踪压缩进度的进度。 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);
}
这很好用,但是我需要线程,它提供有关在此方法中不实现的进度的反馈,但在调用它时(为了在Android设备上创建类似于进度条的东西)。所以这更像是一个架构问题。关于如何解决的任何想法?
答案 0 :(得分:2)
我同时通过添加接口作为参数来覆盖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;
}
然后通过类似的东西调用
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)));
}
});
我现在面临的唯一挑战是限制控制台上的输出而不是每个字节[4096]但是让我们说每两兆字节。我试过这样的事情:
while (-1 != (n = input.read(buffer)))
{
output.write(buffer,0,n);
count += n;
while(n % 2097152 == 0)
{
listener.onProgress(n);
}
}
return count;
但这并没有给我任何输出
答案 1 :(得分:1)
您应该在 AsyncTask 中实现复制机制。 它在后台线程上运行,但您可以使用 publishProgress 方法发布进度。 在此之后,您可以使用 AsyncTask 的 onProgressUpdate 回调在UI线程上处理这些事件。
@Override
protected void onProgressUpdate(final Double... values) {
super.onProgressUpdate(values);
//...
}
编辑: 例如:
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();
}
}
答案 2 :(得分:1)
我对JohnPlata提出的解决方案有一个非常类似的解决方案。我从copy
获取了IOUtils
方法并添加了两个参数:要复制的文件的原始文件大小和用于更新进度的侦听器。我的副本在解压缩.gz
文件时发生,因为解压缩的文件大约是打包文件的3倍,我估计最终结果文件大小(因此行copy(in, out, inputFile.length()*3, progressListener);
)。整个过程都是基于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;
}
调用所有这些内容的类的代码如下所示:
File ungzippedFile = Util.unGzip(movedFile, offlineDataDirFile, new ProgressListener() {
@Override
public void onProgressUpdate(int percentage) {
notificationBuilder.setProgress(100, percentage, false);
notificationManagerCompat.notify(1, notificationBuilder.build());
}
});
该类还包含接口:
public interface ProgressListener {
void onProgressUpdate(int percentage);
}