Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Как изменить часть строк в файле?


Автор: erslgoeirjh 5.5.2012, 11:10
Есть текстовой файл data.txt , состоящий из 10 строк. Как изменить 9 и 10 строки в этом файле, а остальные (1--8) оставить без изменения?

Автор: LSD 5.5.2012, 11:57
Смотря что подразумевается под "изменить". Если изменить это заменить символ X на Y, то можно обойтись RandomAccessFile. Если же строка в результате поменяет длину (или еще как изменится количество байт в строке), то проще создать новый файл, записать туда первые 9 строк без изменения, записать 9 и 10 измененные строки. Удалить старый файл, а новый переименовать.

Автор: Pawl 10.5.2012, 23:03
Цитата(LSD @  5.5.2012,  11:57 Найти цитируемый пост)
Если же строка в результате поменяет длину (или еще как изменится количество байт в строке), то проще создать новый файл, записать туда первые 9 строк без изменения, записать 9 и 10 измененные строки. Удалить старый файл, а новый переименовать.

Может, и проще, но иногда работа с одним файлом - жесткое требование заказчика.
Я делал похожую задачу, только малость сложнее. Мне надо было заменить в файле регулярное выражение определенным символом. Кстати, помогли мне это сделать тут, на форуме, а также я нашел статью с примером, как увеличивать/уменьшать размер файла. Свой код я тут приведу, Вам надо будет его только малость упростить. К примеру, я читал в буфер из файла посимвольно, в объект StringBuilder и проверял, есть ли в этом объекте искомое регулярное выражение. Если нет, читал дальше, а если да - преобразовывал StringBuilder в строку, делал в ней замену, сравнивал длину новой строки со старой, если нужно - изменял размер файла, записывал в него новую строку и читал файл дальше. Вам же можно просто считать 8 строк (хотя бы redLine'ом), а 9-ю и 10-ю последовательно сверить по длине с соответствующими новыми строками, при необходимости каждый раз изменять длину файла и писать в файл новые строки, как это сделано у меня.
Код

import java.io.RandomAccessFile;
import java.io.IOException;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Replacer {

    public static void replace(String fileName, String replable, String replacer) throws IOException, IllegalArgumentException {
        Charset cs = Charset.defaultCharset();
        Pattern p = Pattern.compile(replable);
        try (RandomAccessFile r = new RandomAccessFile(fileName, "rw"); FileChannel file = r.getChannel()) {
            Mover er = new Mover(fileName, "rw");
            int i = 1;
            long currentPosition = 0, position = 0;
            StringBuilder sb = new StringBuilder();
            while (currentPosition < file.size()) {
                Matcher m = p.matcher(sb);
                /**
                 * записываем в буфер байты до тех пор, пока в строке
                 * не встретится искомое регулярное выражение
                 */
                if (!m.find()) {
                    sb.delete(0, sb.length());
                    file.position(position);
                    ByteBuffer buffer = ByteBuffer.allocate(i++);
                    int read = file.read(buffer);
                    buffer.rewind();
                    CharBuffer chbuf = cs.decode(buffer);
                    sb.append(chbuf);
                    currentPosition++;
                } else {
                    currentPosition = position;
                    String str = new String(sb);
                    sb.delete(0, sb.length());
                    String oldStr = str;
                    str = str.replaceAll(replable, replacer);
                    if (str.length() != oldStr.length()) {
                        /**
                         * если размер заменяемого выражения не совпадает с заменяющим
                         * текстом, сдвигаем байты в файле и изменяем его размер
                         */
                        er.move(str.getBytes().length - oldStr.getBytes().length, file.position());
                    }
                    /**
                     * записываем в файл изменённую строку и переводим курсор в следующую
                     * позицию для чтения
                     */
                    file.position(position);
                    file.write(getByts(str));
                    position += str.length();
                    i = 1;
                }
            }
        }
    }

    private static ByteBuffer getByts(String s) {
        ByteBuffer b = ByteBuffer.wrap(s.getBytes());
        return b;
    }

    public static void main(String[] args) {
        try {
            replace("!!!.txt", "\\d+", "I");
        } catch (IOException | IllegalArgumentException e) {
            e.printStackTrace();
        }
    }
}

Код

package chantest;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Mover extends RandomAccessFile {
   /**
    * Буффер для для чтения и записи в файл
    */
   private byte[] buffer = new byte[8192];

   public Mover(String name, String mode) throws FileNotFoundException {
      super(name, mode);
   }

   public Mover(File file, String mode) throws FileNotFoundException {
      super(file, mode);
   }

   public void move(int pos, long off) throws IOException {
      long oldLength = length();
      if (off < oldLength) {
         /**
          * Если смещение меньше длины файла, т.е. вставляем как
          * бы в середину файла...
         
         /**
          * Точка начиная с которой будем двигать куски файла в конец
          * buffer.length -размер передвигаемого куска
          */
         long startChunk = oldLength - buffer.length;
         while (true) {
            /**
             * Сначала передвигаем куски равные buffer.length
             */
            if (startChunk >= off) {
               seek(startChunk);
               readFully(buffer);
               seek(startChunk + pos);
               write(buffer);
            } else {
                /**
                 * В конце обычно остается кусок меньше buffer.length
                 * соответственно читаем не весь буфер, а только часть
                 */
               seek(off);
               int chunkLength = (int)(buffer.length + startChunk - off);
               readFully(buffer, 0, chunkLength);
               /**
                * Изменяем длину файла на длину вставляемого массива
                */
               setLength(oldLength + pos);              
               seek(off + pos);
               write(buffer, 0, chunkLength);
               break;
            }
            startChunk -= buffer.length;
         }
      } else {
         /**
          * Если смещение больше длины файла,
          * ничего сохранять и перемещать ненадо, просто увеличиваем файл:
          */
         setLength(off + pos);
      }
   }
}


Добавлено через 3 минуты и 49 секунд
Странно, почему текст кода не отформатировался... Вроде, правильно код вставлял.

Автор: priam220 12.5.2012, 20:20
прочитать файл (в вашем случае можно целиком) в строку ,изменить там все как нужно, reg ex'ом например, и перезаписать:

Код

 public static void main(String[] args) throws IOException {
 BufferedWriter bw = new BufferedWriter(new FileWriter("/home/txt.txt"));
 bw.write ("text");
 bw.newLine();
 bw.flush();
 bw.close();
    }

Автор: Pawl 12.5.2012, 22:39
Цитата(priam220 @  12.5.2012,  20:20 Найти цитируемый пост)
прочитать файл (в вашем случае можно целиком)

Вообще да, для ДАННОГО случая - это самый простой вариант smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)