- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
出于各种原因,我有一个自定义序列化,我将一些相当简单的对象转储到数据文件中。可能有 5-10 个类,生成的对象图是非循环的并且非常简单(每个序列化对象都有 1 或 2 个对另一个序列化对象的引用)。例如:
class Foo
{
final private long id;
public Foo(long id, /* other stuff */) { ... }
}
class Bar
{
final private long id;
final private Foo foo;
public Bar(long id, Foo foo, /* other stuff */) { ... }
}
class Baz
{
final private long id;
final private List<Bar> barList;
public Baz(long id, List<Bar> barList, /* other stuff */) { ... }
}
id字段只是为了序列化,所以当我序列化到一个文件时,我可以通过记录到目前为止已经序列化了哪些ID来编写对象,然后为每个对象检查它的子对象是否已经被序列化序列化并写入那些没有序列化的,最后通过写入其数据字段和与其子对象对应的 ID 来写入对象本身。
令我困惑的是如何分配 id。想了想,分配ID好像有3种情况:
我该如何正确处理这些问题?我觉得我正在重新发明轮子,并且必须有一种完善的技术来处理所有情况。
澄清:正如一些无关紧要的信息,我正在查看的文件格式大致如下(掩盖了一些不相关的细节)。它经过优化,可以处理相当大量的密集二进制数据(数十/数百 MB),并能够在其中散布结构化数据。密集的二进制数据占文件大小的 99.9%。
该文件由一系列作为容器的纠错 block 组成。每个 block 都可以被认为包含一个由一系列数据包组成的字节数组。可以一次一个地连续读取数据包(例如,可以判断每个数据包的结尾在哪里,然后下一个数据包立即开始)。
所以文件可以被认为是存储在纠错层之上的一系列数据包。这些数据包中的绝大多数是不透明的二进制数据,与本题无关。然而,这些数据包中的一小部分是包含序列化结构化数据的项目,形成了一种由数据“岛”组成的“群岛”,这些“岛”可以通过对象引用关系链接起来。
所以我可能有一个文件,其中数据包 2971 包含一个序列化的 Foo,数据包 12083 包含一个序列化的 Bar,它引用数据包 2971 中的 Foo。(数据包 0-2970 和 2972-12082 是不透明数据包)
所有这些数据包都是不可变的(因此考虑到 Java 对象构造的约束,它们形成了一个非循环对象图)所以我不必处理可变性问题。它们也是通用 Item
接口(interface)的后代。我想做的是将任意 Item
对象写入文件。如果 Item
包含对文件中已有的其他 Item
的引用,我也需要将它们写入文件,但前提是它们尚未写入.否则,当我读回它们时,我将需要以某种方式合并重复项。
最佳答案
你真的需要这样做吗?在内部,ObjectOutputStream
跟踪哪些对象已经被序列化。同一对象的后续写入仅存储内部引用(类似于只写出 id)而不是再次写出整个对象。
参见 Serialization Cache了解更多详情。
如果 ID 对应于某些外部定义的身份,例如实体 ID,那么这是有道理的。但问题指出,生成 ID 纯粹是为了跟踪哪些对象被序列化。
您可以通过 readResolve
方法处理单例。一种简单的方法是将新反序列化的实例与您的单例实例进行比较,如果匹配,则返回单例实例而不是反序列化的实例。例如
private Object readResolve() {
return (this.equals(SINGLETON)) ? SINGLETON : this;
// or simply
// return SINGLETON;
}
编辑:作为对评论的回应,流主要是二进制数据(以优化格式存储),复杂对象分散在该数据中。这可以通过使用支持子流的流格式来处理,例如zip,或简单的 block 分块。例如。流可以是一系列 block :
offset 0 - block type
offset 4 - block length N
offset 8 - N bytes of data
...
offset N+8 start of next block
然后您可以拥有用于二进制数据的 block 、用于序列化数据的 block 、用于 XStream 序列化数据的 block 等。由于每个 block 都知道它的大小,因此您可以创建一个子流以从文件中的位置读取该长度。这使您可以自由混合数据而无需担心解析。
要实现一个流,让你的主流解析 block ,例如
DataInputStream main = new DataInputStream(input);
int blockType = main.readInt();
int blockLength = main.readInt();
// next N bytes are the data
LimitInputStream data = new LimitInputStream(main, blockLength);
if (blockType==BINARY) {
handleBinaryBlock(new DataInputStream(data));
}
else if (blockType==OBJECTSTREAM) {
deserialize(new ObjectInputStream(data));
}
else
...
LimitInputStream
的草图如下所示:
public class LimitInputStream extends FilterInputStream
{
private int bytesRead;
private int limit;
/** Reads up to limit bytes from in */
public LimitInputStream(InputStream in, int limit) {
super(in);
this.limit = limit;
}
public int read(byte[] data, int offs, int len) throws IOException {
if (len==0) return 0; // read() contract mandates this
if (bytesRead==limit)
return -1;
int toRead = Math.min(limit-bytesRead, len);
int actuallyRead = super.read(data, offs, toRead);
if (actuallyRead==-1)
throw new UnexpectedEOFException();
bytesRead += actuallyRead;
return actuallyRead;
}
// similarly for the other read() methods
// don't propagate to underlying stream
public void close() { }
}
关于java:为自定义序列化分配对象引用 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2998100/
出现在 python 2.7.8 中。 3.4.1 不会发生这种情况。 示例: >>> id(id) 140117478913736 >>> id(id) 140117478913736 >>> id
好吧,我对动态创建的控件的 ID 很困惑。 Public Class TestClass Inherits Panel Implements INamingContainer
我收到下面的错误,说有堆栈溢出。发生这种情况是因为带有 IN (id, id, id...id) 的 SQL 语句有大量参数。有没有什么办法解决这一问题?这是在我使用 Eclipse 的本地环境中发生
为什么 CPython(不知道其他 Python 实现)有以下行为? tuple1 = () tuple2 = ()
为什么 CPython(对其他 Python 实现一无所知)有以下行为? tuple1 = () tuple2 = ()
非常简单的问题:当我有一个持久对象时,它通常有一个名为 ID 的属性(对于抽象类)。 那么..命名约定是ID还是Id? 例如。 public int ID { get; set; } 或 public
知道为什么我会收到此错误,我已经尝试了所有命名约定(小写/大写) 我正在使用 Vaadin,这是我的代码片段: public class Usercontainer extends BeanI
为什么 CPython(不知道其他 Python 实现)有以下行为? tuple1 = () tuple2 = ()
我需要改变表的所有主键 UPDATE TODO SET id = id + 1 但我做不到(Demo 来自 Ahmad Al-Mutawa 的回答)描述了原因。主键不能这样改。 我也不能根据这是 sq
我正在尝试列出与用户相关的讨论列表。 想象一下,如果你愿意的话: posts -------------------------------------------------------------
我有一个表,其中包含一些具有自己的 ID 和共享 SKU key 的文章。我尝试使用左连接进行查询,并使用组结果获取从查询返回的所有 id。 我的数据结构是这样的: id - name -
在下表People中: id name 1 James 2 Yun 3 Ethan 如果我想找到最大 ID,我可以运行此查询 select max(id) id from People; 结果是
我正在产品页面上创建评论模块,其中显示垃圾评论选项,并显示 onclick 显示和隐藏弹出窗口。现在它在单个评论中工作正常但是当评论是两个时它同时打开两个因为类是相同的。现在这就是为什么我想要获取父
根据 REST 哲学,PUT操作应该(取自维基百科): PUT http://example.com/resources/142 Update the address member of the co
我想知道如何在使用 PHP 或 JavaScript 进行身份验证后从 Google Analytics 获取 Property Id、View Id 和 Account Id?因为我希望能够将它们存
我想使用所选按钮的 ID 进行删除。但我不知道如何从中获取/获取 id。我尝试了 this.id 但不起作用。 这是我创建按钮的地方: var deleteEmployer= document.cre
我有一个具有以下结构的表“表” ID LinkedWith 12 13 13 12 14 13 15 14 16
请不要在未阅读问题的情况下将问题标记为重复。我确实发布了一个类似的问题,但 STACKOVERFLOW 社区成员要求我单独重新发布修改后的问题,因为考虑到一个小而微妙的修改,解决方案要复杂得多。 假设
在 Android Studio 中,我创建了一个 Person.java 类。我使用Generate 创建了getter 和setter 以及构造函数。 这是我的 Person.java 类: pu
如何在 jQuery 中制作这样的东西: //这是显示的主体 ID //当我悬停 #hover-id 时,我希望 #principal-id 消失并更改 。但是当我将光标放在 #this-id 上时
我是一名优秀的程序员,十分优秀!