java - 如何替换arff文件中的数据?

标签 java arff

我有一个 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();

最佳答案

要澄清一些事情:

<小时/>
FileWriter fw = new FileWriter("colon.arff", true);

在您的 FileWriter 声明中,您使用 boolean 附加标志作为 true,这可以附加到提供的文件。考虑到您希望写入文件的数据与正在读取的文件的格式完全相同,我不确定这是否真的是您想要的。您不希望任何内容被附加到该文件中,从而扭曲原始内容格式。

<小时/>
toWrite += line;

在循环中进行这样的串联从来都不是一个好主意(是的,为了简单的事情和演示目的,我仍然时不时地这样做)。循环外的简单连接是可以的,因为编译器无论如何都会使用 StringBuilder(如果编译器认为这样做更有利的话)。出于以下原因,最好使用 StringBuilder 类:

在Java中,字符串对象是不可变的,这意味着一旦创建,就无法更改它。因此,当我们将一个字符串与另一个字符串连接时,会创建一个新字符串,并将旧字符串标记为垃圾收集器。假设我们需要连接一百万个字符串。然后,我们将创建 100 万个额外的字符串,这些字符串最终将被垃圾回收。

为了解决这个问题,使用了StringBuilder类。它的工作原理就像一个可变的 String 对象。 StringBuilder#append() 方法有助于避免字符串连接中所需的所有复制。要在您的情况下使用 StringBuilder,您需要在 while 循环上方声明构建器:

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());
}

关于java - 如何替换arff文件中的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58576268/

相关文章:

machine-learning - WEKA 使用类值来解决决策树?

weka - Arff 文件 - 标题中未声明标称值。

machine-learning - 如何在arff文件中表示n-gram特征?

java - 如何在weblogic服务器9.2上设置代理

java - 将对象转换为子类对象而不丢失对该对象的引用

java - Hibernate 5.2.10 DDL 自动更新到 AWS RDS (MySql 5.6.10a) 创建 TINYBLOB for Instant

java - 为什么主线程在这里没有被抢占?

python - .arff 文件与 scikit-learn?

machine-learning - 如何使用 Java 中的 Weka 将文本转换为 TF-IDF 格式?

java - Double 没有从一个方法传递到另一个方法