MahanGM
MahanGM

Reputation: 2382

Read/Write string binary data - BinaryReader

I wrote the below method to archive files into one file using binary mode:

        // Compile archive
        public void CompileArchive(string FilePath, ListView FilesList, Label Status, ProgressBar Progress)
        {
            FileTemplate TempFile = new FileTemplate();
            if (FilesList.Items.Count > 0)
            {
                BinaryWriter Writer = new BinaryWriter(File.Open(FilePath, FileMode.Create), System.Text.Encoding.ASCII);
                Progress.Maximum = FilesList.Items.Count - 1;
                Writer.Write((long)FilesList.Items.Count);
                for (int i = 0; i <= FilesList.Items.Count - 1; i++)
                {
                    TempFile.Name = FilesList.Items[i].SubItems[1].Text;
                    TempFile.Path = "%ARCHIVE%";
                    TempFile.Data = this.ReadFileData(FilesList.Items[i].SubItems[2].Text + "\\" + TempFile.Name);
                    Writer.Write(TempFile.Name);
                    Writer.Write(TempFile.Path);
                    Writer.Write(TempFile.Data);
                    Status.Text = "Status: Writing '" + TempFile.Name + "'";
                    Progress.Value = i;
                }
                Writer.Close();
                Status.Text = "Status: None";
                Progress.Value = 0;
            }
        }

I read files data using ReadFileData which is in the above method method which return a string of data. (StreamReader) Next up I extract my archive. Everything is done great but the data which will being stored in the extraction method doesn't give me a right data so the extracted files have not right data to show their original functionality.

Extract method:

    // Extract archive
    public void ExtractArchive(string ArchivePath, string ExtractPath, ListView FilesList, Label Status, ProgressBar Progress)
    {
        FileTemplate TempFile = new FileTemplate();
        BinaryReader Reader = new BinaryReader(File.Open(ArchivePath, FileMode.Open), System.Text.Encoding.ASCII);
        long Count = Reader.ReadInt64();
        if (Count > 0)
        {
            Progress.Maximum = (int)Count - 1;
            FilesList.Items.Clear();
            for (int i = 0; i <= Count - 1; i++)
            {
                TempFile.Name = Reader.ReadString();
                TempFile.Path = Reader.ReadString();
                TempFile.Data = Reader.ReadString();
                Status.Text = "Status: Reading '" + TempFile.Name + "'";
                Progress.Value = i;
                if (!Directory.Exists(ExtractPath))
                {
                    Directory.CreateDirectory(ExtractPath);
                }
                BinaryWriter Writer = new BinaryWriter(File.Open(ExtractPath + "\\" + TempFile.Name, FileMode.Create), System.Text.Encoding.ASCII);
                Writer.Write(TempFile.Data);
                Writer.Close();
                string[] ItemArr = new string[] { i.ToString(), TempFile.Name, TempFile.Path };
                ListViewItem ListItem = new ListViewItem(ItemArr);
                FilesList.Items.Add(ListItem);
            }
            Reader.Close();
            Status.Text = "Status: None";
            Progress.Value = 0;
        }
    }

The structure:

struct FileTemplate
        {
            public string Name, Path, Data;
        }

Thanks.

Upvotes: 5

Views: 7902

Answers (3)

Felix K.
Felix K.

Reputation: 6281

Consider using byte arrays for write and safe the data.

Byte array( write )

Byte[] bytes = File.ReadAllBytes(..);
// Write it into your stream
myStream.Write(bytes.Count);
myStream.Write(bytes, 0, bytes.Count);

Byte array ( read )

Int32 byteCount = myStream.ReadInt32();
Byte[] bytes = new Byte[byteCount];
myStream.Read(bytes, 0, byteCount);

Upvotes: 2

svick
svick

Reputation: 244757

If your Data can be binary data, then you shouldn't have them in a string. They should be a byte[].

When you write a string using the ASCII encoding like you do, and try to write binary data, many of the bytes (treated as Unicode characters) can't be encoded and so you end up with damaged data.

Morale of the story: never treat binary data as text.

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062492

The example of an icon makes it clear; you are using string-based APIs to handle data that isn't strings (icons are not string-based). More, you are usig ASCII, so only characters in the 0-127 range would ever be correct. Basically, you can't do that. You need to handle binary data using binary methods (perhaps using the Stream API).

Other options:

  • use serialization to store instances of objects with the data properties and a BLOB (byte[]) for the content
  • use something like zip (maybe SharpZipLib) which does somethig very similar, essentially

Upvotes: 0

Related Questions