Ham*_*aya 5 java file-io inputstream
是否有关于如何以特定速率读取长文件的文章/算法?
假设我不想在发出读取时传递10 KB /秒.
And*_*son 12
一个简单的解决方案,通过创建ThrottledInputStream.
这应该像这样使用:
final InputStream slowIS = new ThrottledInputStream(new BufferedInputStream(new FileInputStream("c:\\file.txt"),8000),300);
Run Code Online (Sandbox Code Playgroud)
300是每秒千字节数.8000是BufferedInputStream的块大小.
这当然应该通过实现read(byte b [],int off,int len)来概括,这将为您节省大量的System.currentTimeMillis()调用.对于每个读取的字节,都会调用System.currentTimeMillis()一次,这会导致一些开销.还应该可以存储可以节省读取的字节数,而无需调用System.currentTimeMillis().
确保在它们之间放置一个BufferedInputStream,否则将以单个字节而不是块来轮询FileInputStream.这将使CPU负载从10%减少到几乎为0.您将有可能超过数据速率乘以块大小的字节数.
import java.io.InputStream;
import java.io.IOException;
public class ThrottledInputStream extends InputStream {
private final InputStream rawStream;
private long totalBytesRead;
private long startTimeMillis;
private static final int BYTES_PER_KILOBYTE = 1024;
private static final int MILLIS_PER_SECOND = 1000;
private final int ratePerMillis;
public ThrottledInputStream(InputStream rawStream, int kBytesPersecond) {
this.rawStream = rawStream;
ratePerMillis = kBytesPersecond * BYTES_PER_KILOBYTE / MILLIS_PER_SECOND;
}
@Override
public int read() throws IOException {
if (startTimeMillis == 0) {
startTimeMillis = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long interval = now - startTimeMillis;
//see if we are too fast..
if (interval * ratePerMillis < totalBytesRead + 1) { //+1 because we are reading 1 byte
try {
final long sleepTime = ratePerMillis / (totalBytesRead + 1) - interval; // will most likely only be relevant on the first few passes
Thread.sleep(Math.max(1, sleepTime));
} catch (InterruptedException e) {//never realized what that is good for :)
}
}
totalBytesRead += 1;
return rawStream.read();
}
}
Run Code Online (Sandbox Code Playgroud)
粗略的解决方案是一次读取一个块,然后睡眠,例如 10k,然后睡眠一秒钟。但我要问的第一个问题是:为什么?有几个可能的答案:
我的建议是不要把它控制在阅读层面。这有点混乱和不准确。相反,在工作结束时控制它。Java 有很多很棒的并发工具来处理这个问题。有几种替代方法可以做到这一点。
我倾向于使用生产者消费者模式来解决此类问题。它为您提供了很好的选择,可以通过报告线程等来监控进度,并且它可以是一个非常干净的解决方案。
类似ArrayBlockingQueue的东西可以用于 (1) 和 (2) 所需的那种限制。由于容量有限,当队列已满时,读取器最终会阻塞,因此不会填得太快。可以控制工人(消费者)只工作得如此快,以限制覆盖率(2)。