- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一个应用程序,该应用程序可以处理二进制文件中的大量整数(最多 50 meg)。我需要尽快完成此操作,主要的性能问题是磁盘访问时间,因为我从磁盘进行大量读取,优化读取时间通常会提高应用程序的性能。
到目前为止,我认为将文件分割成的 block 越少(即我读取的数据越少/读取的大小越大),我的应用程序的运行速度就越快。这是因为 HDD 由于其机械特性,在查找(即定位 block 的开头)时速度非常慢。但是,一旦它找到了您要求它读取的 block 的开头,它应该会相当快地执行实际读取。
嗯,直到我运行这个测试:
Old test removed, had issues due to HDD Caching
新测试(HDD 缓存在这里没有帮助,因为文件太大(1GB)并且我访问其中的随机位置):
int mega = 1024 * 1024;
int giga = 1024 * 1024 * 1024;
byte[] bigBlock = new byte[mega];
int hundredKilo = mega / 10;
byte[][] smallBlocks = new byte[10][hundredKilo];
String location = "C:\\Users\\Vladimir\\Downloads\\boom.avi";
RandomAccessFile raf;
FileInputStream f;
long start;
long end;
int position;
java.util.Random rand = new java.util.Random();
int bigBufferTotalReadTime = 0;
int smallBufferTotalReadTime = 0;
for (int j = 0; j < 100; j++)
{
position = rand.nextInt(giga);
raf = new RandomAccessFile(location, "r");
raf.seek((long) position);
f = new FileInputStream(raf.getFD());
start = System.currentTimeMillis();
f.read(bigBlock);
end = System.currentTimeMillis();
bigBufferTotalReadTime += end - start;
f.close();
}
for (int j = 0; j < 100; j++)
{
position = rand.nextInt(giga);
raf = new RandomAccessFile(location, "r");
raf.seek((long) position);
f = new FileInputStream(raf.getFD());
start = System.currentTimeMillis();
for (int i = 0; i < 10; i++)
{
f.read(smallBlocks[i]);
}
end = System.currentTimeMillis();
smallBufferTotalReadTime += end - start;
f.close();
}
System.out.println("Average performance of small buffer: " + (smallBufferTotalReadTime / 100));
System.out.println("Average performance of big buffer: " + (bigBufferTotalReadTime / 100));
结果:小缓冲区的平均值 - 35ms大缓冲区的平均值 - 40 毫秒?!(在Linux和Windows上尝试过,在这两种情况下,较大的 block 大小都会导致较长的读取时间,为什么?)
多次运行此测试后,我意识到,出于某种神奇的原因,读取一个大块平均比顺序读取 10 个较小尺寸的 block 花费更长的时间。我认为这可能是 Windows 过于智能并试图优化其文件系统中的某些内容的结果,因此我在 Linux 上运行了相同的代码,令我惊讶的是,我得到了相同的结果。
我不知道为什么会发生这种情况,有人可以给我提示吗?在这种情况下,最佳的 block 大小是多少?
亲切的问候
最佳答案
第一次读取数据后,数据会在磁盘缓存中。第二次读取应该快得多。您需要首先运行您认为更快的测试。 ;)
如果您有 50 MB 内存,您应该能够一次读取整个文件。
<小时/>package com.google.code.java.core.files;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileReadingMain {
public static void main(String... args) throws IOException {
File temp = File.createTempFile("deleteme", "zeros");
FileOutputStream fos = new FileOutputStream(temp);
fos.write(new byte[50 * 1024 * 1024]);
fos.close();
for (int i = 0; i < 3; i++)
for (int blockSize = 1024 * 1024; blockSize >= 512; blockSize /= 2) {
readFileNIO(temp, blockSize);
readFile(temp, blockSize);
}
}
private static void readFile(File temp, int blockSize) throws IOException {
long start = System.nanoTime();
byte[] bytes = new byte[blockSize];
int r;
for (r = 0; System.nanoTime() - start < 2e9; r++) {
FileInputStream fis = new FileInputStream(temp);
while (fis.read(bytes) > 0) ;
fis.close();
}
long time = System.nanoTime() - start;
System.out.printf("IO: Reading took %.3f ms using %,d byte blocks%n", time / r / 1e6, blockSize);
}
private static void readFileNIO(File temp, int blockSize) throws IOException {
long start = System.nanoTime();
ByteBuffer bytes = ByteBuffer.allocateDirect(blockSize);
int r;
for (r = 0; System.nanoTime() - start < 2e9; r++) {
FileChannel fc = new FileInputStream(temp).getChannel();
while (fc.read(bytes) > 0) {
bytes.clear();
}
fc.close();
}
long time = System.nanoTime() - start;
System.out.printf("NIO: Reading took %.3f ms using %,d byte blocks%n", time / r / 1e6, blockSize);
}
}
在我的笔记本电脑上打印
NIO: Reading took 57.255 ms using 1,048,576 byte blocks
IO: Reading took 112.943 ms using 1,048,576 byte blocks
NIO: Reading took 48.860 ms using 524,288 byte blocks
IO: Reading took 78.002 ms using 524,288 byte blocks
NIO: Reading took 41.474 ms using 262,144 byte blocks
IO: Reading took 61.744 ms using 262,144 byte blocks
NIO: Reading took 41.336 ms using 131,072 byte blocks
IO: Reading took 56.264 ms using 131,072 byte blocks
NIO: Reading took 42.184 ms using 65,536 byte blocks
IO: Reading took 64.700 ms using 65,536 byte blocks
NIO: Reading took 41.595 ms using 32,768 byte blocks <= fastest for NIO
IO: Reading took 49.385 ms using 32,768 byte blocks <= fastest for IO
NIO: Reading took 49.676 ms using 16,384 byte blocks
IO: Reading took 59.731 ms using 16,384 byte blocks
NIO: Reading took 55.596 ms using 8,192 byte blocks
IO: Reading took 74.191 ms using 8,192 byte blocks
NIO: Reading took 77.148 ms using 4,096 byte blocks
IO: Reading took 84.943 ms using 4,096 byte blocks
NIO: Reading took 104.242 ms using 2,048 byte blocks
IO: Reading took 112.768 ms using 2,048 byte blocks
NIO: Reading took 177.214 ms using 1,024 byte blocks
IO: Reading took 185.006 ms using 1,024 byte blocks
NIO: Reading took 303.164 ms using 512 byte blocks
IO: Reading took 316.487 ms using 512 byte blocks
看来最佳读取大小可能是 32KB。注意:由于文件完全位于磁盘缓存中,因此这可能不是从磁盘读取的文件的最佳大小。
关于java - FileInputStream、JAVA 的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6714317/
这可能有点傻,但我想知道后台操作的区别。 InputStream is = new FileInputStream(filepath); FileInputStream is = new FileIn
优点: 所以,我有这个二进制数据文件(大小 - 恰好 640631 字节),我正试图让 Java 读取它。 我有两个可互换的类实现为读取该数据的层。其中之一使用 RandomAccessFile,效果
问题是当我在 Android Studio 中运行我的程序时,FileInputStream 找不到 c:\poi-test.xls 文件。 我在 Android Studio 中运行的简单测试 ja
Scanner scanner= new Scanner(new File("target.txt")); 和 FileInputStream d = new FileInputStream("tar
我有 @Component public class CodesConverterService { private final FileInputStreamFactory fileInput
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
我正在创建一个程序,用于根据 iTunes 播放列表文件从用户的计算机播放音乐。当我尝试根据播放列表文本文件中提供的位置打开音频文件时,它说存在错误。 filename = "Macintosh HD
我需要读取的文件如下所示: 30 15 6 3 12 20 3 4 (没有要点) inputStream 没有读取 30 和 15,但它正在读取所有其他的。 如何让 inputStream 读取第一行
我收到“找不到文件!”无论我做什么。 FileInputStream fin; try { fin = new FileInputStream("foo.txt");
public static void main(String[] args) { try { File f = new File("file.txt");
我正在加载另一个类通过 FileOutputstream 方法保存的文件。无论如何,我想在另一个类中加载该文件,但它要么给我语法错误,要么使我的应用程序崩溃。 我能找到的唯一教程是在同一个类中保存和加
我在 res/raw 中有一个名为“pack.dat”的原始文件。 我可以使用以下代码打开一个InputStream: InputStream fis = null; try {
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求提供代码的问题必须表现出对所解决问题的最低限度的了解。包括尝试的解决方案、为什么它们不起作用以及预期结果
我已经对我的代码进行了 klocwork 代码分析。我收到以下错误我终于关闭了输入流即使那样我也收到错误“fileInputStream”在退出时未关闭。 下面是一段代码 LOGGER.log
我想逐个标记地读取 file.txt 文件中的单词,并向每个标记添加词性标记,然后将其写入 file2.text 文件。 file.txt 内容已标记化。这是我的代码。 public class Po
“Dbconnection.java”“db.properties”文件找不到该文件。我向您展示如何获取以下文件。 我的下一个项目目录。 源代码 数据库 DbConnection.java db.pr
如果我将文本文件放在同一项目文件夹中,程序可以毫无问题地读取它。但是我怎样才能让它从我的计算机中的某个地方读取文件(例如:在桌面中) FileInputStream fstream = new Fil
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
这是我将位图转换为字节数组的代码。 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); image.compress
我是 Java 编码的新手,遇到了很多困难。我假设使用从文件中读取的 bufferedreader 编写一个程序,我已经创建了名为“scores.txt”的文件。所以我有一个名为 processFil
我是一名优秀的程序员,十分优秀!