如何实现Mail对象与String互转以存入YAML文件?
解决Mail对象无限制字符的序列化/反序列化问题
针对你不想限制邮件内容/主题字符的需求,给你几个可行的方案:
方案1:直接用YAML序列化Mail对象(最推荐)
既然你本来就用.yml文件存储,没必要自己转成String再存,直接用YAML库序列化整个List<Mail>对象更省心,原生支持任意字符,还不用自己处理拆分逻辑。
以常用的SnakeYAML库为例:
- 引入依赖(Maven):
<dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>2.2</version> </dependency>
- 序列化(写入YAML):
List<Mail> mails = ...; // 你的邮件列表 DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); Yaml yaml = new Yaml(options); try (FileWriter writer = new FileWriter("mails.yml")) { yaml.dump(mails, writer); }
- 反序列化(读取YAML):
Yaml yaml = new Yaml(new Constructor(Mail.class)); try (FileReader reader = new FileReader("mails.yml")) { List<Mail> mails = yaml.load(reader); }
注意:要确保Mail类有无参构造器,或者给SnakeYAML配置自定义构造器适配你现有的带String参数的构造器(如果不想加无参构造的话)。
方案2:分隔符转义法
如果坚持要自己转String,可以对字段中的分隔符做转义处理,比如用#作为分隔符,但提前把字段里的#替换成\#,同时把\替换成\\(避免转义字符冲突)。
修改Mail类的toString()和构造器:
@Override public String toString() { // 转义字段中的\和# String escapedSender = _sender.replace("\\", "\\\\").replace("#", "\\#"); String escapedDate = _date.replace("\\", "\\\\").replace("#", "\\#"); String escapedTopic = _topic.replace("\\", "\\\\").replace("#", "\\#"); String escapedContent = _content.replace("\\", "\\\\").replace("#", "\\#"); return escapedSender + "#" + escapedDate + "#" + escapedTopic + "#" + escapedContent; } public Mail(String mailStr) { // 先按非转义的#拆分(用正则匹配未被转义的#) String[] parts = mailStr.split("(?<!\\\\)#"); // 反转义每个字段 _sender = parts[0].replace("\\#", "#").replace("\\\\", "\\"); _date = parts[1].replace("\\#", "#").replace("\\\\", "\\"); _topic = parts[2].replace("\\#", "#").replace("\\\\", "\\"); _content = parts[3].replace("\\#", "#").replace("\\\\", "\\"); }
这个方法能支持任意字符,但需要处理转义逻辑,相对繁琐。
方案3:长度前缀法
给每个字段前面加上该字段的字符长度,拆分时先读取长度,再截取对应长度的内容,完全不受字段内字符影响。
修改Mail类的toString()和构造器:
@Override public String toString() { // 用|作为长度和内容的分隔符(不会和长度数字冲突) return _sender.length() + "|" + _sender + "|" + _date.length() + "|" + _date + "|" + _topic.length() + "|" + _topic + "|" + _content.length() + "|" + _content; } public Mail(String mailStr) { int index = 0; // 读取sender int lenEnd = mailStr.indexOf("|", index); int senderLen = Integer.parseInt(mailStr.substring(index, lenEnd)); index = lenEnd + 1; _sender = mailStr.substring(index, index + senderLen); index += senderLen + 1; // 跳过分隔符 // 读取date lenEnd = mailStr.indexOf("|", index); int dateLen = Integer.parseInt(mailStr.substring(index, lenEnd)); index = lenEnd + 1; _date = mailStr.substring(index, index + dateLen); index += dateLen + 1; // 读取topic lenEnd = mailStr.indexOf("|", index); int topicLen = Integer.parseInt(mailStr.substring(index, lenEnd)); index = lenEnd + 1; _topic = mailStr.substring(index, index + topicLen); index += topicLen + 1; // 读取content(最后一段) lenEnd = mailStr.indexOf("|", index); int contentLen = Integer.parseInt(mailStr.substring(index, lenEnd)); index = lenEnd + 1; _content = mailStr.substring(index, index + contentLen); }
这个方法逻辑清晰,不会有字符冲突问题,实现起来也直观。
内容的提问来源于stack exchange,提问作者gegenphase
相关产品推荐
相关产品推荐

