我对LIS文件一无所知,因此这将是关于二进制文件的一般内容.
许多二进制文件格式将具有某种类型的索引,以及实际的数据条目本身.因此,读取文件将包括扫描整个索引,直到找到您要查找的内容,然后跳到索引中指定的偏移量.索引可以定义在文件开头的块中,也可以定义为分布在整个文件中的链表.实际的形式可能会复杂得多,但作为一个简化的心理模型可能会很有用.
如果您知道格式,您可以简单地使用BinaryReader来读取值,并相应地在文件中跳转.可能是使用某种状态机来跟踪您正在阅读的内容.
在文件的任意位置插入数据
这是really difficult分才能做得好.您将不得不在浪费空间、移动数据和碎片之间做出 Select .数据库花费了大量的精力试图在每个极端之间找到一个令人满意的中间结果.
但是,如果您使用的是现有格式,则会为您做出 Select .如果该格式不是为廉价的插入而设计的,那么您可能需要移动文件中的绝大多数数据,基本上需要您重写整个内容.如果您幸运的话,这种格式可能允许以较低的成本追加数据.
如果该格式不是为廉价修改而设计的,那么您很可能需要将其转换为修改成本为is%的格式.如果你能把它们都保存在内存中,那很可能会让事情变得简单.
您还可以将索引解析到内存 struct 中,并将任何更新保留在内存中,直到将数据写回磁盘.因此,想象中的格式可能是这样的.这里的关键是您只需要从磁盘读取最少的数据量,并且添加或修改是在内存中完成的.请注意,这仅用于说明目的.
public class Index
{
private readonly Dictionary<string, IEntry> entries = new();
public IEnumerable<string> List => entries.Keys;
public byte[] Read(string key) => entries[key].Read();
public void UpdateOrAdd(string key, byte[] data) => entries[key] = new MemoryEntry(data);
public static Index Load(Stream source)
{
var br = new BinaryReader(source);
var numEntries = br.ReadInt32();
var result = new Index();
for (int i = 0; i < numEntries; i++)
{
var key = br.ReadString();
var length = br.ReadInt32();
// Note. Mixing index information and data like this will make it
// easy to read/append, but slower to load.
var offset = (int)br.BaseStream.Position;
result.entries[key] = new FileEntry(source, offset, length);
br.BaseStream.Position += length;
}
return result;
}
public void Save(Stream destination)
{
var bw = new BinaryWriter(destination);
bw.Write(entries.Count);
var list = entries.ToList();
foreach (var (key, value) in list)
{
bw.Write(key);
bw.Write(value.Length);
value.CopyTo(bw.BaseStream);
}
}
}
public interface IEntry
{
public void CopyTo(Stream destination);
public byte[] Read();
public int Length { get; }
}
public class MemoryEntry : IEntry
{
private readonly byte[] data;
public MemoryEntry(byte[] data) => this.data = data;
public void CopyTo(Stream destination) => destination.Write(data, 0, data.Length);
public byte[] Read() => data;
public int Length => data.Length;
}
public class FileEntry : IEntry
{
private readonly Stream fileStream;
private readonly int offset;
private readonly int length;
public FileEntry(Stream fileStream, int offset, int length)
{
this.fileStream = fileStream;
this.offset = offset;
this.length = length;
}
public void CopyTo(Stream destination)
{
fileStream.Position = offset;
fileStream.CopyTo(destination, length);
}
public byte[] Read()
{
fileStream.Position = offset;
var result = new byte[length];
fileStream.Position = offset;
var bytesRead = fileStream.Read(result, 0, length);
if (bytesRead != length) throw new InvalidOperationException("Invalid binary format");
return result;
}
public int Length => length;
}