Изменить файл .txt в Java - PullRequest
28 голосов
/ 05 мая 2009

У меня есть текстовый файл, который я хочу редактировать, используя Java. В нем много тысяч строк. Я в основном хочу перебрать строки и изменить / редактировать / удалить текст. Это должно случаться довольно часто.

Из решений, которые я видел на других сайтах, общий подход выглядит так:

  • Открыть существующий файл с помощью BufferedReader
  • Читать каждую строку, вносить изменения в каждую строку и добавлять ее в StringBuilder
  • Как только весь текст прочитан и изменен, запишите содержимое StringBuilder в новый файл
  • Заменить старый файл новым файлом

Мне кажется, что это решение немного "хакерское", особенно если в моем текстовом файле тысячи строк.

Кто-нибудь знает лучшее решение?

Ответы [ 11 ]

30 голосов
/ 05 мая 2009

Я недавно не делал этого на Java, но запись всего файла в память кажется плохой идеей.

Лучшая идея, которую я могу придумать, - это одновременно открыть временный файл в режиме записи, и для каждой строки прочитать его, при необходимости изменить, а затем записать во временный файл. В конце удалите оригинал и переименуйте временный файл.

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

5 голосов
/ 05 мая 2009

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

Вы можете использовать apache IOUtils, который имеет метод, подобный следующему.

public static String readFile(String filename) throws IOException {
    File file = new File(filename);
    int len = (int) file.length();
    byte[] bytes = new byte[len];
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(file);
        assert len == fis.read(bytes);
    } catch (IOException e) {
        close(fis);
        throw e;
    }
    return new String(bytes, "UTF-8");
}

public static void writeFile(String filename, String text) throws IOException {
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(filename);
        fos.write(text.getBytes("UTF-8"));
    } catch (IOException e) {
        close(fos);
        throw e;
    }
}

public static void close(Closeable closeable) {
    try {
        closeable.close();
    } catch(IOException ignored) {
    }
}
2 голосов
/ 05 мая 2009

Что это за данные? Вы контролируете формат файла?

Если файл содержит пары имя / значение (или аналогичные), вам может повезти с Свойства или, возможно, скомбинировать что-либо с помощью драйвера JDBC для плоских файлов.

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

2 голосов
/ 05 мая 2009

Нет причин для буферизации всего файла.

Просто напишите каждую строку как прочитанную, вставьте строки при необходимости, удалите строки при необходимости, замените строки при необходимости.

По сути, вам не придется заново создавать файл оптом, особенно если это просто текстовый файл.

2 голосов
/ 05 мая 2009

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

1 голос
/ 28 марта 2014

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

Поэтому в моем примере я установил длину строки равной 100 и добавив пробел при создании файла и обратной записи в файл.

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

public class RandomAccessFileUtil {
public static final long RECORD_LENGTH = 100;
public static final String EMPTY_STRING = " ";
public static final String CRLF = "\n";

public static final String PATHNAME = "/home/mjiang/JM/mahtew.txt";

/**
 *  one two three
    Text to be appended with
    five six seven
    eight nine ten
 * 
 * 
 * @param args
 * @throws IOException
 */
public static void main(String[] args) throws IOException
{
    String starPrefix = "Text to be appended with";
    String replacedString = "new text has been appended";

    RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");

    String line = "";
    while((line = file.readLine()) != null)
    {
        if(line.startsWith(starPrefix))
        {
            file.seek(file.getFilePointer() - RECORD_LENGTH - 1);
            file.writeBytes(replacedString);
        }

    }
}

public static void createFile() throws IOException
{
    RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");

    String line1 = "one two three";
    String line2 = "Text to be appended with";
    String line3 = "five six seven";
    String line4 = "eight nine ten";

    file.writeBytes(paddingRight(line1));
    file.writeBytes(CRLF);
    file.writeBytes(paddingRight(line2));
    file.writeBytes(CRLF);
    file.writeBytes(paddingRight(line3));
    file.writeBytes(CRLF);
    file.writeBytes(paddingRight(line4));
    file.writeBytes(CRLF);

    file.close();

    System.out.println(String.format("File is created in [%s]", PATHNAME));
}

public static String paddingRight(String source)
{
    StringBuilder result = new StringBuilder(100);
    if(source != null)
    {
        result.append(source);
        for (int i = 0; i < RECORD_LENGTH - source.length(); i++)
        {
            result.append(EMPTY_STRING);
        }
    }

    return result.toString();
}

}

1 голос
/ 04 апреля 2012

Хотя этот вопрос был опубликован некоторое время назад, я думаю, что было бы хорошо, чтобы выложить мой ответ здесь. Я думаю, что в этом сценарии лучше всего использовать пакет FileChannel из java.nio.channels. Но это только в том случае, если вам нужна хорошая производительность! Вам необходимо получить FileChannel через RandomAccessFile, например:

java.nio.channels.FileChannel channel = new java.io.RandomAccessFile("/my/fyle/path", "rw").getChannel();

После этого вам нужно создать ByteBuffer, где вы будете читать из FileChannel.

это выглядит примерно так:


java.nio.ByteBuffer inBuffer = java.nio.ByteBuffer.allocate(100);
int pos = 0;
int aux = 0;
StringBuilder sb = new StringBuilder();

while (pos != -1) {

    aux = channel.read(inBuffer, pos);
    pos = (aux != -1) ? pos + aux : -1;

    b = inBuffer.array();
    sb.delete(0, sb.length());

    for (int i = 0; i < b.length; ++i) {

         sb.append((char)b[i]);

    }

    //here you can do your stuff on sb

    inBuffer = ByteBuffer.allocate(100);

}

Надеюсь, что мой ответ вам поможет!

1 голос
/ 11 октября 2009

Думаю, FileOutputStream.getFileChannel() очень поможет, смотрите FileChannel api http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html

1 голос
/ 10 мая 2009

Разве вы не можете использовать регулярные выражения, если знаете, что хотите изменить? Джакарта Regexp , вероятно, должны добиться цели.

1 голос
/ 05 мая 2009

Как правило, вы не можете редактировать файл на месте; это просто очень длинная последовательность символов, которая включает символы новой строки. Вы можете редактировать на месте, если ваши изменения не меняют количество символов в каждой строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...