FilePut does not prepend the two length bytes when writing a string to a binary file from C#. FilePutObject throws exceptions on classes/structs

浪尽此生 提交于 2020-01-13 19:46:53

问题


I have a app that needs to be both read and write compatible with a VB6 binary file. I learned about the Microsoft.VisualBasic.FileSystem class and I am trying to write out a structure to the file.

FileSystem.FileOpen(file, "test.bin", Microsoft.VisualBasic.OpenMode.Binary);

FileSystem.FilePut(file, patch.intTest);
FileSystem.FilePut(file, patch.dateTest);
FileSystem.FilePut(file, patch.stringTest, StringIsFixedLength: false);
FileSystem.FilePut(file, patch.boolTest);

Everything writes correctly if I put each item individually except the string. When the VB6 app writes the string it prepends two length bytes, my code does not.

In the MSDN it says Binary mode removes the length bytes unless it is in a structure. Setting StringIsFixedLength to true should of done that, but it appears that Binary mode over rides that setting.

I try to use FilePutObject and try to pass in a struct or class (which is what the msdn says you need to do to get the bytes to show up) it throws the exception

System.ArgumentException occurred
  Message=File I/O with type 'PatchFileStructure' is not valid.
  Source=Microsoft.VisualBasic
  StackTrace:
       at Microsoft.VisualBasic.FileSystem.FilePutObject(Int32 FileNumber, Object Value, Int64 RecordNumber)
       at SandboxConsole.Sandbox.Main(String[] args) in E:\Code\Sandbox Console\SandboxConsole\Program.cs:line 41
  InnerException: 

Full code

using System;
using Microsoft.VisualBasic;

namespace SandboxConsole
{
    static class Sandbox
    {
        public struct PatchFileStructure
        {
            public Int32 intTest { get; set; }
            public DateTime dateTest { get; set; }
            public string stringTest { get; set; }
            public bool boolTest { get; set; }
        }

        public static void Main(params string[] args)
        {
            var patch = new PatchFileStructure()
            {
                intTest = 5,
                dateTest = new DateTime(1999, 1, 1, 1, 1, 1),
                stringTest = "Test Name",
                boolTest = true,
            };

            int file = FileSystem.FreeFile();

            FileSystem.Kill("test.bin");

            FileSystem.FileOpen(file, "test.bin", Microsoft.VisualBasic.OpenMode.Binary);

            FileSystem.FilePutObject(file, patch);

            //FileSystem.FilePut(file, patch.intTest);
            //FileSystem.FilePut(file, patch.dateTest);
            //FileSystem.FilePut(file, patch.stringTest, StringIsFixedLength: false);
            //FileSystem.FilePut(file, patch.boolTest);

            FileSystem.FileClose(file);
        }
    }
}

Here are my two files I am comparing. Spaces are added to the c# version to illustrate the problem.

vb6 - 05 00 00 00 24 F6 1D 5B 21 A8 E1 40 09 00 54 65 73 74 20 4E 61 6D 65 FF FF
C#  - 05 00 00 00 24 F6 1D 5B 21 A8 E1 40       54 65 73 74 20 4E 61 6D 65 FF FF

If I try to read the vb6 file from the C# everything works fine except the string, which returns null.


回答1:


FilePutObject seems to be a lot more verbose and write out more metadata than is needed, primarily for variants.
Have you tried just:

FileSystem.FilePut(file, patch);

This uses the "ValueType" overload.




回答2:


You can write the length out explicitly before the string:

FileSystem.FilePut(file, patch.stringTest.Lenght.ToInt16);
FileSystem.FilePut(file, patch.stringTest, StringIsFixedLength: false);



回答3:


Change to:

FileSystem.FilePut(file, patch.stringTest, StringIsFixedLength: false);

The system isn't writing the length prefix because you're telling it the string is fixed length.



来源:https://stackoverflow.com/questions/8070425/fileput-does-not-prepend-the-two-length-bytes-when-writing-a-string-to-a-binary

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!