Вставка текста в существующий файл через Java

Я хотел бы создать простую программу (на Java), которая редактирует текстовые файлы, в частности ту, которая выполняет вставку произвольных фрагментов текста в случайные позиции в текстовом файле. Эта функция является частью более крупной программы, которую я сейчас пишу.

Читая описание java.util.RandomAccessFile, кажется, что любые операции записи, выполняемые в середине файла, фактически перезаписывают существующее содержимое. Это побочный эффект, которого я хотел бы избежать (если это возможно).

Есть ли простой способ добиться этого?

Заранее спасибо.


person Dinuk    schedule 14.11.2008    source источник
comment
Просто чтобы вы понимали, это не просто ограничение в Java. Примерно так работает весь ввод-вывод. Это функциональность, которую предоставляет базовая ОС.   -  person Lou Franco    schedule 14.11.2008
comment
Возможно, существует реализация файловой системы, которая поддерживает что-то вроде блоков данных связанного списка, которые, вероятно, могут позволить быструю вставку данных в середину файла. Однако для этого потребуются довольно низкоуровневые системные вызовы.   -  person Benedikt Waldvogel    schedule 06.12.2008
comment
Я не могу найти точную статью, но я прочитал одну, объясняющую, как использовать веревку в качестве структуры данных, управляющей простым текстовым редактором. en.wikipedia.org/wiki/Rope_%28computer_science%29   -  person Albert    schedule 21.05.2009


Ответы (7)


Хорошо, этот вопрос довольно старый, но FileChannels существуют с Java 1.4, и я не знаю, почему они нигде не упоминаются при решении проблемы замены или вставки содержимого в файлы. FileChannels работают быстро, используйте их.

Вот пример (игнорируя исключения и некоторые другие вещи):

public void insert(String filename, long offset, byte[] content) {
  RandomAccessFile r = new RandomAccessFile(new File(filename), "rw");
  RandomAccessFile rtemp = new RandomAccessFile(new File(filename + "~"), "rw");
  long fileSize = r.length();
  FileChannel sourceChannel = r.getChannel();
  FileChannel targetChannel = rtemp.getChannel();
  sourceChannel.transferTo(offset, (fileSize - offset), targetChannel);
  sourceChannel.truncate(offset);
  r.seek(offset);
  r.write(content);
  long newOffset = r.getFilePointer();
  targetChannel.position(0L);
  sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset));
  sourceChannel.close();
  targetChannel.close();
}
person xor_eq    schedule 10.07.2013
comment
Могу ли я использовать FileChannel для наложения текста на изображение? - person Yohanes AI; 27.07.2017
comment
Вообще говоря, вы можете использовать FileChannels для изменения любых файлов любым удобным для вас способом. Однако дело в том, что для всех случаев использования, которые я могу себе представить, вам нужно знать, что писать в файл. Если ваше изображение представляет собой .SVG, вы, конечно, можете использовать FileChannel для записи необходимого xml-элемента в файл. Но поскольку ваш вопрос не был таким конкретным, ответ таков: нет, потому что вы не знаете, что делаете. . Вы можете взглянуть на классы java.awt.Image и особенно на класс BufferedImage и, возможно, прочитать учебник об этом и начать оттуда. - person xor_eq; 27.07.2017
comment
Да, после некоторых исследований. Я использую объект Graphic вместо FileChannel. - person Yohanes AI; 27.07.2017

Ну, нет, я не верю, что есть способ избежать перезаписи существующего контента с помощью одного стандартного вызова Java IO API.

Если файлы не слишком велики, просто прочитайте весь файл в ArrayList (по одной записи на строку) и либо перепишите записи, либо вставьте новые записи для новых строк.

Затем перезапишите существующий файл новым содержимым или переместите существующий файл в резервную копию и запишите новый файл.

В зависимости от того, насколько сложными должны быть изменения, может потребоваться изменить структуру данных.

Другим методом может быть чтение символов из существующего файла при записи в отредактированный файл и редактирование потока по мере его чтения.

person Ken Gentle    schedule 14.11.2008

Если в Java есть способ отображать файлы памяти, то вы можете расширить файл до его новой длины, отобразить файл, переместить все байты в память до конца, чтобы сделать дыру, и записать новые данные в дыру.

Это работает на C. Никогда не пробовал на Java.

Другой способ, о котором я только что подумал, сделать то же самое, но со случайным доступом к файлам.

  • Искать до конца - 1 МБ
  • Читать 1 МБ
  • Запишите это в исходное положение + размер зазора.
  • Повторите для каждого предыдущего 1 МБ, работая по направлению к началу файла.
  • Остановитесь, когда достигнете желаемого положения зазора.

Используйте больший размер буфера для повышения производительности.

person Zan Lynx    schedule 21.05.2009
comment
Да, для этой цели в Java есть: docs.oracle.com/javase/6/docs/api/java/nio/channels/ - person Jerry Tian; 23.08.2018

Вы можете использовать следующий код:

BufferedReader reader = null;
BufferedWriter writer = null;
ArrayList list = new ArrayList();

try {
    reader = new BufferedReader(new FileReader(fileName));
    String tmp;
    while ((tmp = reader.readLine()) != null)
        list.add(tmp);
    OUtil.closeReader(reader);

    list.add(0, "Start Text");
    list.add("End Text");

    writer = new BufferedWriter(new FileWriter(fileName));
    for (int i = 0; i < list.size(); i++)
        writer.write(list.get(i) + "\r\n");
} catch (Exception e) {
    e.printStackTrace();
} finally {
    OUtil.closeReader(reader);
    OUtil.closeWriter(writer);
}
person S.Yavari    schedule 04.06.2011

Я не знаю, есть ли удобный способ сделать это прямо, иначе

  • прочитать начало файла и записать его в цель
  • напишите свой новый текст для цели
  • прочитайте остальную часть файла и запишите его в цель.

О цели: вы можете создать новое содержимое файла в памяти, а затем перезаписать старое содержимое файла, если обрабатываемые файлы не такие большие. Или вы можете записать результат во временный файл.

Это, вероятно, было бы проще всего сделать с потоками, RandomAccessFile, похоже, не предназначен для вставки посередине (на самом деле). При необходимости см. руководство.

person Touko    schedule 14.11.2008

Я считаю, что единственный способ вставить текст в существующий текстовый файл — это прочитать исходный файл и записать содержимое во временный файл с вставленным новым текстом. Затем сотрите исходный файл и переименуйте временный файл в исходное имя.

Этот пример предназначен для вставки одной строки в существующий файл, но все же может быть вам полезен.

person Brendan Cashman    schedule 14.11.2008

Если это текстовый файл, прочтите существующий файл в StringBuffer и добавьте новое содержимое в тот же StringBuffer, теперь вы можете записать SrtingBuffer в файл. так что теперь файл содержит как существующий, так и новый текст.

person Community    schedule 23.09.2009