Есть ли способ эффективный создать файл с заданным размером в Java?
В C это можно сделать с помощью ftruncate (см. этот ответ).
Большинство людей просто записывают в файл фиктивные байты




Вы можете открыть файл для записи, найти смещение (n-1) и записать один байт. ОС автоматически расширит файл до желаемого количества байтов.
ск: В целом да. На практике это зависит от специфики базовой ОС и может потребовать некоторых действий, чтобы сделать файл разреженным.
В Unix и Linux это будет разреженный файл - один блок из нулевых байтов, кроме записанного одного байта (который, конечно, также может быть нулевым).
В Windows (NTFS) и OS-X (HFS +) вы не получите разреженный файл.
Создайте новый RandomAccessFile и вызовите метод setLength, указав желаемую длину файла. Базовая реализация JRE должна использовать наиболее эффективный метод, доступный в вашей среде.
Следующая программа
import java.io.*;
class Test {
public static void main(String args[]) throws Exception {
RandomAccessFile f = new RandomAccessFile("t", "rw");
f.setLength(1024 * 1024 * 1024);
}
}
на машине Linux выделит пространство с помощью ftruncate (2)
6070 open("t", O_RDWR|O_CREAT, 0666) = 4
6070 fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
6070 lseek(4, 0, SEEK_CUR) = 0
6070 ftruncate(4, 1073741824) = 0
в то время как на машине Solaris он будет использовать функцию F_FREESP64 системного вызова fcntl (2).
/2: open64("t", O_RDWR|O_CREAT, 0666) = 14
/2: fstat64(14, 0xFE4FF810) = 0
/2: llseek(14, 0, SEEK_CUR) = 0
/2: fcntl(14, F_FREESP64, 0xFE4FF998) = 0
В обоих случаях это приведет к созданию разреженного файла.
Как вы записывали эти трассировки вызовов библиотеки? ^^
Это трассировки системных вызовов. Я использовал strace (1) под Linux и truss (1) под Solaris.
В javadoc написано, что «В этом случае содержимое расширенной части файла не определено». Гарантирует ли это обнуление в Windows и Linux, или есть какой-нибудь эффективный способ убедиться, что все байты нули?
Я ожидал, что любая ОС (включая Windows и Linux) обнулит байты, чтобы избежать утечки старых данных, принадлежащих другому пользователю. Однако я могу думать о сценариях, в которых этого не было бы: старые данные, принадлежащие тому же процессу, или небольшая (J2ME) платформа.
Блестяще. Я использовал его, чтобы протестировать приложение для Android в условиях «SD-карта заполнена»!
Интересно, что RandomAccessFile.setLength() API также заполняет файл нулями, что иногда может быть очень полезно.
@Sandeep это неверно. В Javadoc прямо говорится, что «содержимое расширенной части файла не определено». Нули могут быть поведением на конкретной платформе.
Действительно ли вышеупомянутый ответ работает? Единственное, что создано в моей тестовой системе (виртуальная машина CentOS 5.6), похоже, является ПУСТОЙ файл, который сообщает о «выделенном» размере с помощью метода length (), который может быть сколь угодно большим независимо от доступного пространства. Если вы откроете файл и напишете несколько символов, размер файла изменится до нескольких байтов. Метод getFreeSpace () класса File сообщает об одном и том же объеме доступного пространства до и после «создания» файла, и вы можете использовать свободное дисковое пространство раздела, как если бы созданного файла там не было, независимо от того, насколько велик предустановленная длина составляет.
Файл заданного размера не должен занимать такое количество байтов. Многие системы поддерживают разреженные файлы (это то, что вы видите), когда пустые части файла не хранятся на диске. Другие системы могут поддерживать сжатые файлы, где объем используемого хранилища зависит от того, насколько сжимаемо содержимое файла.
Работает так, как ожидалось, но есть ли способы настроить этот подход для создания уникальных файлов (какие значения MD5 отличаются)? @DiomidisSpinellis
Чтобы сделать файлы уникальными, создайте их другой длины или добавьте UUID в начало или конец файла.
Я считаю, что это плохое решение, размер на диске не будет соответствовать длине файла, который вам нужен.
В исходном вопросе конкретно задан вопрос о создании разреженного файла. Для разреженных файлов по определению требуется меньше места, чем их длина.
Начиная с Java 8, этот метод работает в Linux и Windows:
final ByteBuffer buf = ByteBuffer.allocate(4).putInt(2);
buf.rewind();
final OpenOption[] options = { StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW , StandardOpenOption.SPARSE };
final Path hugeFile = Paths.get("hugefile.txt");
try (final SeekableByteChannel channel = Files.newByteChannel(hugeFile, options);) {
channel.position(HUGE_FILE_SIZE);
channel.write(buf);
}
Большое спасибо @mandev. Работал как шарм !!
Будет ли полученный файл разреженным?