假设我有一种文件格式,它由一系列对象组成,其中每个对象都有以下格式的标题:
一些注意事项:
由于我正在使用
public struct FileObjectHeader {
//The type of the object (not important for this question, but it exists)
public byte TypeID;
//The length of the object's data, which DOES NOT include the size of the header.
public UInt16 Length;
}
紧随其后是指定长度的数据。
我首先为每个对象和对象头创建位置列表,然后读取这些数据:
struct FileObjectIndex {
public FileObjectHeader Header;
public long Location;
}
public List<FileObject> ReadObjects(Stream s) {
List<FileObjectReference> objectRefs = new List<FileObjectReference>();
try {
while (true) {
FileObjectHeader header = ReadObjectHeader(s);
//The above advances the stream by the size of the header as well.
FileObjectReference reference = new FileObjectReference() { Header = header, Position = stream.Position };
objectRefs.add(reference);
//Advance the stream to the next object's header.
s.Seek(header.Length, SeekOrigin.Current);
}
} catch (EndOfStreamException) {
//Do nothing as this is an expected case
}
//Now we'd read all of the objects that we've previously located.
//This code isn't too important for the question but I'm including it for reference.
List<FileObject> objects = new List<FileObject>();
foreach (var reference in objectRefs) {
s.seek(reference.Location, SeekOrigin.Begin);
objects.add(ReadObject(reference.Header, s));
}
return objects;
}
一些注意事项:
- 如果
ReadObjectHeader
和ReadObject
方法无法读取所有所需数据(即到达流的末尾),它们将抛出EndOfStreamException异常。 - 我在这里使用Seek方法是因为对象可以引用其他对象,而且还有逻辑来确保父对象在其子对象之前加载(文件格式没有保证父对象位于子对象之前)。 我没有在上面的示例代码中包含它,因为这会使示例变得复杂,但它不会改进示例。
- 在大多数情况下,这可能是只读的
FileStream
,但我不能保证。 但是,对于这种情况,我主要担心FileStream。
由于我正在使用
FileStream.seek
,是否有可能导致超出流的末尾并无限扩展文件的情况? 根据文档:
这种说法似乎表明它可能会在没有我扩展文件的情况下扩展文件,因为它从头文件中读取3个字节。 实际上,似乎不会发生这种情况,但我想确认它不会发生。您可以搜索超过流的任何位置。 当您搜索超过文件长度时,文件大小会增加。 在Windows NT及更高版本中,添加到文件末尾的数据设置为零。 在Windows 98或早期版本中,添加到文件末尾的数据未设置为零,这意味着之前删除的数据对流是可见的。
FileAccess.Read
打开文件,因此没有任何操作会更改文件... 请查看参考源以获取确切的详细信息。 - Alexei Levenkov