使用 RandomAccessFile 的最佳方式是 Java

Posted

技术标签:

【中文标题】使用 RandomAccessFile 的最佳方式是 Java【英文标题】:Best way to use RandomAccessFile is Java 【发布时间】:2019-02-11 07:00:24 【问题描述】:

我正在创建一个实用程序,它使用 RandomAccessFile 将 MSSQL 表 blob 写入数据磁盘文件。它太慢了,因为我们需要始终寻找最后一个位置并写入流内容..请让我知道任何其他替代方法来加速随机访问文件的写入。

我有超过 5000 万条记录,按照目前的逻辑大约需要 10 个小时。

我的代码块是这样的:

RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
InputStream inputStream = null;

while (rows.hasNext()) 
    Row row = rows.next();
    inputStream = (InputStream) row.getValues()[0];
    offset = randomAccessFile.length();
    byte[] buffer = new byte[8196];
    int count;
    randomAccessFile.seek(offset);
    randomAccessFile.setLength(offset);
    while ((count = inputStream.read(buffer)) != -1) 
        randomAccessFile.write(buffer, 0, count);
    

randomAccessFile.close();   

【问题讨论】:

您需要从特定位置写入文件吗?只是想了解您选择 RandomAccessFile 的原因。你也可以使用 BufferedWriter。 写入 50 MB 的数据需要一秒钟。您可以通过仅写入此大小的空白数据来进行测试。如果超过这个,是时候从数据库中提取数据了。 Btw setLength 在 Java 9 和 10 中非常慢。这在 Java 8 和 11 中很好。 【参考方案1】:

根据您发布的代码,您只需附加到现有文件即可。在追加模式下使用缓冲写入器可以更轻松、更高效地完成此操作。

因此,使用

BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardOpenOptions.CREATE, StandardOpenOptions.APPEND);

改为。

彼得评论后更新:对于输出流,整个事情基本相同,只是Files 没有“缓冲”部分的便利功能。因此:

OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(file.toPath(), StandardOpenOption.CREATE, StandardOpenOption.APPEND));

【讨论】:

Writers 用于编写文本。 OP 可能想要一个 BufferedOutputStream。 我们也需要写入二进制数据,我们不知道表中的数据是什么。【参考方案2】:

目前,您在每次迭代中写入大约 8 Kb (8196 / 1024) 的数据,并且每次迭代都会执行 I/O 操作,这会阻塞且需要时间。尝试将其增加到至少 1 Mb 大约(10,000,000)。

byte[] buffer = new byte[10000000];

【讨论】:

大于 32KB 的缓冲区可能会变慢,因为它们不适合 L1 数据缓存。 是的..我有一行内容为 1KB 数据,所以我认为当前大小还可以。

以上是关于使用 RandomAccessFile 的最佳方式是 Java的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 文件中间写入字节的最佳方法

在 Java 文件中间写入字节的最佳方法

文件处理RandomAccessFile

Java 实现文件随机读写-RandomAccessFile

RandomAccessFile的用法

Java 核心编程——文件随机读写类(RandomAccessFile)