#java #memory-management #large-files
#java #управление памятью #большие файлы
Вопрос:
Мне нужно объединить два очень больших файла (> 1G каждый), записав 4 строки из первого в выходной файл, а затем записать 4 из второго. И так далее до конца. Оба файла имеют одинаковое количество строк, и это число делится на четыре. Какой наиболее эффективный способ сделать это в Java?
Комментарии:
1. Размер файла не так важен. Это то, как вы это читаете.
2. Я бы предположил, что прочитайте 4 строки из одного, запишите их, прочитайте 4 строки из другого, запишите их. Для повышения эффективности используйте буферизованные устройства чтения / записи.
3. Вероятно, более эффективно не использовать Java. Правильная комбинация инструментов командной строки Linux, вероятно, будет быстрее.
4. как насчет разделения файла на небольшие фрагменты (разделяй и властвуй)? 1. подсчитайте общее количество строк в файле 2. разделите файл на фрагменты, используя общее количество строк 3. для каждого фрагмента создайте объединенный файл. 4. объедините объединенный файл в результат.
5. @kingori, это может сработать, но это излишне сложно. Нет ничего плохого в том, чтобы просто открывать и читать оба файла последовательно; вам нужно одновременно хранить в памяти только 8 строк (по 4 из каждого файла), поэтому не имеет значения, насколько велики файлы.
Ответ №1:
Я люблю использовать Decorator
шаблон. Создайте два класса, каждый класс представляет экземпляр BufferedReader.
Например,
class First
{
BufferedReader br;
...
public String getLine()
{
return br.readLine();
}
}
class Second
{
BufferedReader br;
...
public String [] getLines()
{
//read four lines and return it
}
}
Ответ №2:
попробуйте это и посмотрите, сколько времени это займет. соответствующим образом отрегулируйте n. если это слишком медленно, попробуйте использовать nio.
import java.io.*;
class Time {
Time() {}
long dt() {
return System.currentTimeMillis() - t0;
}
final long t0 = System.currentTimeMillis();
}
public class Main {
public static void create(File file1, File file2, int n) throws Exception {
BufferedWriter bw1 = new BufferedWriter(new FileWriter(file1));
write(bw1, n, "foo");
bw1.close();
BufferedWriter bw2 = new BufferedWriter(new FileWriter(file2));
write(bw2, n, "bar");
bw2.close();
}
private static void write(BufferedWriter bw, int n, String line) throws IOException {
for (int i = 0; i < n; i ) {
bw.write(line);
bw.write(lineSeparator);
}
}
private static void write4(BufferedReader br1, BufferedWriter bw, String line) throws IOException {
bw.write(line);
bw.write(lineSeparator);
for (int i = 0; i < 3; i ) {
line = br1.readLine();
bw.write(line);
bw.write(lineSeparator);
}
}
public static void main(String[] args) throws Exception {
File file1 = new File("file1");
File file2 = new File("file2");
if (!file1.exists()) {
create(file1, file2, 10000000);
}
File file3 = new File("file3");
Time time=new Time();
BufferedReader br1 = new BufferedReader(new FileReader(file1));
BufferedReader br2 = new BufferedReader(new FileReader(file2));
BufferedWriter bw = new BufferedWriter(new FileWriter(file3));
String line1, line2;
while ((line1 = br1.readLine()) != null) {
write4(br1, bw, line1);
line2 = br2.readLine();
write4(br2, bw, line2);
}
br1.close();
br2.close();
bw.close();
System.out.println(time.dt()/1000. " s.");
}
static final String lineSeparator = System.getProperty("line.separator");
}
Ответ №3:
Извините, если эта идея уже была дана 🙂
Я думаю, что самый быстрый способ сделать это — создать 3 потока. t1 и t2 будут считывать данные из двух входных файлов, у каждого потока будет своя очередь (потокобезопасная), и поток прочитает 4 строки и поместит их в свою очередь. t3 будет потоком записи, он будет взаимозаменяемо считывать узлы из двух очередей и помещать их в новый объединенный файл. Я думаю, что это хорошее решение, потому что оно позволяет выполнять параллельный ввод-вывод для всех трех файлов (а ввод-вывод — это горлышко бутылки здесь ..) и минимальное взаимодействие между потоками.