【问题标题】:Seeking a particular value when using BinaryWriter使用 BinaryWriter 时寻求特定值
【发布时间】:2015-10-31 18:08:39
【问题描述】:

我觉得很难表达自己,所以我会直接进入代码

FileStream stream = new FileStream("//ignoreThis//demo.bin", 
                        FileMode.Append, FileAccess.Write, FileShare.Write));
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(myNum);
writer.Write(myString);

我可以多次调用这个方法,我知道每次我这样做时,它都会在文件'demo.bin'的末尾添加新数据。现在我正在尝试编写一个方法,我可以在其中寻找我的第三个 instance(我不确定我是否可以这样称呼它)。主要问题是变量的大小不同,即使我使用此代码使字符串的“固定”长度为 20 (我知道当有人写一个超过 20 的字符串时它不起作用,但我已经写了验证以确保他们不超过这个限制)

这是我用来使字符串保持恒定长度的代码

public String MakeFixedSize(int length, String inputString)
{
    return inputString.PadRight(length, '\0');
}

据我所知,我在这个程序中使用的 int 的大小和长度都是固定的(不在上面的代码中)

【问题讨论】:

  • 看看MSDN - 是德语,但你可以切换语言,我希望。该代码解释了在使用二进制写入器读取字符串时要做什么。它的要点是二进制写入器将字符串写入为“长度前缀”,因此您可以通过查看前两个字节来判断长度。-但您可以最好使用BinaryFormatter 并序列化数据。见here
  • “直接写入文件夹”是什么意思?每条记录一个文件?
  • 我的意思是文件。我想以可区分的方式分隔每条记录,以便在不使用序列化的情况下加快搜索速度(即使用字节数组并通过 BinaryWriter 存储并通过解析回读取它)。我已经有了解析代码和诸如此类的代码,但我需要一种分离记录的好方法
  • 但是对于可变大小的记录,直接搜索将不起作用。我的例子中的回读是快速而直接的,尽管是在一个记录库的记录上。但是,它不是(显式)解析字节,只是类成员类型。
  • 所以如果我理解正确的话,我需要为字符串或序列化添加前缀(这在这个任务中是不允许的)。我的问题是为什么我最初编写的用于使字符串具有固定大小的代码不能与二进制编写器一起使用,但在使用序列化时却可以正常工作?

标签: seek binarywriter fixed-size-types


【解决方案1】:

有很多方法可以做到这一点,我不确定哪种方法最适合您的情况。

如果您可以并且想要创建严格固定大小的记录,您可以直接寻找合适的位置。对于大量数据,这可能会更快。

或者您可以依靠BinaryWriter 为每个字符串添加两个长度字节的前缀,然后读取正确数量的字符..

如果您想保持更灵活并保持简单,您可以使用BinaryFormatter 进行序列化:

创建一个可序列化的类:

[Serializable]
public class MyClass
{
    public string Name;
    public int Number;
}

然后您可以使用BinaryFormatter 将多个实例写入磁盘:

string fileName = "yourfileName"; 

FileStream stream = new FileStream(fileName, 
                        FileMode.Append, FileAccess.Write, FileShare.Write);
var formatter = new BinaryFormatter();
formatter.Serialize(stream, new MyClass() { Name = "A", Number = 12365 });
formatter.Serialize(stream, new MyClass() { Name = "B", Number = 2365 });
formatter.Serialize(stream, new MyClass() { Name = "C", Number = 365 });
stream.Close();

然后读回来,可能在List<T>,仍然使用相同的格式化程序:

FileStream stream2 = new FileStream(fileName, FileMode.Open, FileAccess.Read);
List<MyClass> myClassList = new List<MyClass>();

while (stream2.Position < stream2.Length)
    myClassList.Add((MyClass)formatter.Deserialize(stream2));

现在你可以访问myClassList[2]..

更新:

看起来你也可以这样做,只要你确定记录长度:

using (BinaryWriter binWriter = new BinaryWriter(File.Open(fileName, FileMode.Create)))
{
    binWriter.Write("RAller");
    binWriter.Write(123);
    binWriter.Write("RoBler");
    binWriter.Write(23);
    binWriter.Write("RolCer");
    binWriter.Write(3);
    binWriter.Write("RolDDr");
    binWriter.Write(423);
    binWriter.Write("REEler");
    binWriter.Write(523);
    binWriter.Write("RFFler");
    binWriter.Write(66);
}

using (BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open)))
{
    // string < 255 seems to get only a one byte length prefix:
    int recLen = 1 + 6 + 4;

    br.BaseStream.Seek(recLen * 3, SeekOrigin.Begin);
    string s = br.ReadString();
    int i = br.ReadInt32();
}

短字符串只获得一个字节长度的计数器:

较长的字符串获取两个字节的前缀,对于可变大小,您必须逐步遍历记录,计算下一个偏移量。

除非数据非常大,否则我无法真正想象您为什么要这样做。

嗯,需求有时就是它们的本质,有时它们需要质疑..

【讨论】:

  • 该任务特别要求我不使用序列化,而是直接存储值。你能扩展一个字符串的前缀吗?我对这个概念不熟悉
  • link 很好地解释了这一点:一个以长度为前缀的字符串表示字符串的长度,它在字符串前面加上一个包含该字符串长度的单个字节或单词。该方法首先将字符串的长度写入为 UTF-7 编码的无符号整数,然后使用 BinaryWriter 实例的当前编码将那么多字符写入流中。 值得研究的代码,你可以看到如何回读各种类型..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多