有没有方法可以在Java中避免将重复的行写入文件?

huangapple go评论76阅读模式
英文:

Is there a way to avoid writing duplicate lines to a file in Java?

问题

我有一个简单的问题:

我有一些在Java中将数据行写入文本文件的代码。写入文件的其中一个方法调用位于一个比数据本身更频繁地被调用的方法内部。

结果,文本文件包含了从此方法写入的每一行的大量重复。我知道我可以事后从文件中删除这些重复项,但我想知道是否有人知道在首次写入文件时避免写入重复行的方法。感谢阅读。

写入数据到文件的方法:

@Override
public void writeMessage(String location, double time, String action) {
	write(location + " " + time + " " + action);
}

调用它的方法:

public int receiveMessage(Message m, DTNHost from) {
	int retVal = this.router.receiveMessage(m, from);

	if (retVal == MessageRouter.RCV_OK) {
		m.addNodeOnPath(this);	// 将此节点添加到消息路径中
	}

	writeMessage(untranslate().toString(), SimClock.getTime(), "receiving message");

	return retVal;
}

untranslate.toString() 返回一对 xy 坐标的字符串,而 SimClock.getTime() 返回一个时间戳。

我的解决方案是定义一个名为 lastMsg 的字符串,在类的构造函数中将其初始化为 null,然后在写入文件之前检查 receiveMessage() 中消息参数的 ID 是否发生了变化:

public int receiveMessage(Message m, DTNHost from) {
	String currentMsg = m.getId();
	int retVal = this.router.receiveMessage(m, from);

	if (retVal == MessageRouter.RCV_OK) {
		m.addNodeOnPath(this);	// 将此节点添加到消息路径中
	}
	if (!(currentMsg.equals(this.lastMsg))) {
		writeMessage(untranslate().toString(), SimClock.getTime(), "receiving message");
		this.lastMsg = currentMsg;
	}
	return retVal;
}
英文:

I have a simple question:

I have some code that writes lines of data to a text file in Java. One of the method calls that writes data to the file is located within a method that is called more frequently than the data itself changes.

As a result, the text file contains numerous duplicates of each line that is written from this method. I know I can remove these duplicates from the file after the fact, but I am wondering if anyone knows of a way to avoid writing duplicate lines to a file in the first place. Thanks for reading.

The method that writes data to the file:

@Override
public void writeMessage(String location, double time, String action) {
	write(location + " " + time + " " + action);
}

And the method that calls it:

public int receiveMessage(Message m, DTNHost from) {
	int retVal = this.router.receiveMessage(m, from);

	if (retVal == MessageRouter.RCV_OK) {
		m.addNodeOnPath(this);	// add this node on the messages path
	}

	writeMessage(untranslate().toString(), SimClock.getTime(), "receiving message");

	return retVal;
}

untranslate.toString() returns a pair of xy coordinates as a string, and SimClock.getTime() returns a timestamp.

My solution was to define a String called lastMsg, initialize it as null in the constructor of the class, and then to check if the ID of the message parameter in receiveMessage() has changed before writing to the file:

public int receiveMessage(Message m, DTNHost from) {
	String currentMsg = m.getId();
	int retVal = this.router.receiveMessage(m, from);

	if (retVal == MessageRouter.RCV_OK) {
		m.addNodeOnPath(this);	// add this node on the messages path
	}
	if (!(currentMsg.equals(this.lastMsg))) {
		writeMessage(untranslate().toString(), SimClock.getTime(), "receiving message");
		this.lastMsg = currentMsg;
	}
	return retVal;
}

答案1

得分: 1

似乎很琐碎;该方法应该检查'previous line written'。如果相同,则return;,什么也不做。如果不同,写入它,并更改'previous line written'字段。

如果您从多个线程调用此方法,那么您已经有了麻烦(如果两个线程同时调用一个写入'Hello!'到文件的方法,您可能会得到一个包含如下内容的文件行:HeHellllo!o! - 您需要一些同步。这样可以保证字段也同步。所以:

private String lastLineWritten = null;

public /* synchronized - you may need this */ void writeLog(String line) {
    if (line == null) throw new NullPointerException();
    if (line.equals(lastLineWritten)) return;
    lastLineWritten = line;
    try (BufferedWriter bw = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)) {
        bw.write(line);
    }
}
英文:

Seems trivial; that method should check 'previous line written'. If the same, return;, doing nothing. If not, write it, and change the 'previous line written' field.

If you're calling this method from multiple threads, you're already in trouble (if two threads both call a method that writes 'Hello!' to a file, you could end up with a file with a line: HeHellllo!o! - you need some synchronization. Which then guarantees the field is synced too. So:

private String lastLineWritten = null;

public /* synchronized - you may need this */ void writeLog(String line) {
    if (line == null) throw new NullPointerException();
    if (line.equals(lastLineWritten)) return;
    lastLineWritten = line;
    try (BufferedWriter bw = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)) {
        bw.write(line);
    }
}

huangapple
  • 本文由 发表于 2020年9月20日 23:59:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63980941.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定