Как заменить данные в файле arff? - PullRequest
0 голосов
/ 27 октября 2019

У меня есть arff-файл, который нужно изменить, сохраняя при этом одну и ту же структуру файла каждый раз, когда я запускаю код.

Например, у меня есть следующий файл arff

@relation australian

@attribute A1 numeric
@attribute A2 numeric
@attribute A3 numeric
@attribute A4 numeric
@attribute A5 numeric
@attribute A6 numeric
@attribute A7 {0,1}

@data
1,3,5,2,4,3,1
3,5,1,2,5,6,0
6,1,4,2,3,4,1

Мне нужно заменять три строки данных на еще три строки каждый раз, когда я запускаю код

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

 BufferedReader reader = new BufferedReader(new FileReader("aa.txt"));
String toWrite = "";
String line = null;
while ((line = reader.readLine()) != null) {
    toWrite += line;
   // System.out.println(toWrite);
}
FileWriter fw = new FileWriter("colon.arff",true);
fw.write(toWrite);
fw.close();

1 Ответ

0 голосов
/ 27 октября 2019

Чтобы очистить пару вещей:


FileWriter fw = new FileWriter("colon.arff", true);

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


toWrite += line;

Выполнение конкатенации в цикле никогда не является хорошей идеей (да,Я до сих пор делаю это время от времени для простых вещей и демонстрационных целей). Простые конкатенации вне цикла - это нормально, так как компилятор использует StringBuilder в любом случае, если он считает, что это будет более выгодно. Просто лучше использовать класс StringBuilder по следующей причине:

В Java строковые объекты являются неизменяемыми, что означает, что после их создания вы не сможете его изменить. Поэтому, когда мы объединяем одну строку с другой, создается новая строка, а более старая помечается для сборщика мусора. Допустим, нам нужно объединить миллион строк. Затем мы создаем 1 миллион дополнительных строк, которые в конечном итоге будут собираться мусором.

Для решения этой проблемы используется класс StringBuilder . Он работает как изменяемый объект String. Метод StringBuilder # append () помогает избежать копирования, требуемого при конкатенации строк. Чтобы использовать StringBuilder в вашем случае, вы должны объявить построитель над циклом , а :

StringBuilder toWrite = new StringBuilder();

, а затем внутри цикла:

toWrite.append(line).append(System.lineSeparator());

Обратите внимание на дополнительные append (System.lineSeparator ()) ? Если вы хотите записать готовую строку в файл с помощью FileWriter , вам нужно добавить разрыв строки («\ n» или «\ r \ n» в зависимости от ОС), чтобы следующая строка былаНужно написать будет на новой строке в файле. В этом случае вы фактически строите строку, которая будет записана в файл с одной записью, поэтому, если добавляемая строка должна находиться в новой строке в файле, необходимо также добавить разрыв строки. Метод System.lineSeparator () возвращает зависящий от операционной системы символ (ы) перевода строки.


Приведенный ниже код выполнит то, что вы просите:

// Demo data to replace in file...
String[] newData = {"4,2,13,1,4,2,0",
                    "1,3,3,5,2,4,1",
                    "7,7,2,1,5,8,1"};

// 'Try With Resourses' is used here to auto-close the reader and writer.
try (BufferedReader reader = new BufferedReader(new FileReader("aa.txt")); 
                             FileWriter fw = new FileWriter("colon.arff")) {
    String ls = System.lineSeparator();  // The Line Break use by OS.
    StringBuilder toWrite = new StringBuilder(); // A String builder object
    int skip = 0; // Used for skipping old file data for placement of the new data
    String line = null; // Use to hold file lines read (one at a time)

    // Start reading file...
    while ((line = reader.readLine()) != null) {
        /* If skip is greater than 0 then read in next line and 
           decrement skip by 1. This is used in case the data 
           in file contains more rows of data than what you are 
           replacing.              */
        if (skip > 0) {
            skip--;
            continue;
        }

        // Append the file line read into the StringBuilder object
        toWrite.append(line).append(ls);

        // If the file line read equals "@data"
        if (line.trim().equals("@data")) {
            /* Append the new data to the toWrite variable here, 
               for example: if the new data was in a string array 
               named newData (see above declaration)...        */
            for (int i = 0; i < newData.length; i++) {
                /* Perform new data Validation...
                   Make sure all values are string representations
                   of numerical data and that the 7th column of data
                   is no less than 0 and no more than 1.          */
                String[] ndParts = newData[i].split("\\s{0,},\\s{0,}"); // Split the current data row
                boolean isValid = true;  // flag
                for (int v = 0; v < ndParts.length; v++) {
                    if (!ndParts[v].matches("\\d+") || 
                            (v == 6 && (!ndParts[v].equals("0") && 
                            !ndParts[v].equals("1")))) {
                        isValid = false;
                        System.err.println("Invalid numerical value supplied on Row " + 
                                (i+1) + " in Column " + (v+1) + ". (Data: " + newData[i] + ")" + 
                                ls + "Not writing data line to file!");
                        break;
                    }
                }
                /* If the current new data row is valid then append
                   it to the build and increment skip by 1.      */
                if (isValid) {
                    toWrite.append(newData[i]).append(ls);
                    skip++;
                }
            }
        }
    }
    // Write the entire built string to file.
    fw.write(toWrite.toString());
}
catch (FileNotFoundException ex) {
    System.err.println(ex.getMessage());
}
catch (IOException ex) {
    System.err.println(ex.getMessage());
}
...