Цитата(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 секунд Странно, почему текст кода не отформатировался... Вроде, правильно код вставлял. |