Jak plik obrazem pamięci wypełnić i nic nie pokręcić
Kontynuując temat z poprzedniego wpisu, obecnie przedstawię, w jaki sposób wypełnić plik, aby odpowiadał obrazowi pamięci oczekiwanemu przez aplikacje nie napisane w .NET (napisane w kodzie niezarządzanym).
W tym wypadku swoją rolę ponownie odegrają klasy BitConvert oraz Encoding. W obu wypadkach użyte zostaną metody o takiej samej nazwie: GetBytes. W pierwszym przypadku metoda ta umożliwia zmianę dowolnego typu na jego reprezentację bajtową (posiada bardzo dużo przeciążeń), czyli zwraca tablicę bajtów o rozmiarze zgodnym z rozmiarem typu zmiennej zajmowanym w pamięci. W przypadku klasy Encoding, metoda GetBytes powoduje przekształcenie tekstu w postaci Unicode do jednobajtowego tekstu w wybranej stronie kodowej. Dodatkowo w tym wypadku należy zadbać do właściwą długość tekstu. Stąd jest on uzupełniany spacjami po prawej stronie (PadRight) oraz obcinany do maksymalnej, dopuszczalnej długości (Substring).
Niezbędna będzie również refaktoryzacja poprzednio zaprezentowanej klasy, aby wydzielić tablicę rozmiarów, obiekt odpowiedzialny za przekształcenie tekstów na prawidłową stronę kodową oraz listę produktów.
class BinaryIO { private List<Product> Products = new List<Product>(); private Encoding CurrentEncoding = Encoding.GetEncoding("windows-1250"); // instancja kodowania dla Windows PL private byte[] Sizes = { sizeof(int), 8, 20, sizeof(short) }; // długości poszczególnych pól struktury starego typu class Product // klasa odzwierciedlająca pobieraną strukturę { public int Identifier { get; set; } public string Symbol { get; set; } public string Name { get; set; } public short Quantity { get; set; } public Product(int aIdentifier, string aSymbol, string aName, short aQuantity) { Identifier = aIdentifier; Symbol = aSymbol; Name = aName; Quantity = aQuantity; } } public void Prepare() { string[] numerals = { "pierwsza", "druga", "trzecia", "czwarta", "piąta" }; for (int f = 0; f < numerals.Length; f++) Products.Add( new Product( 65792 + f, "Symbol" + (char)(f + 65), "Nazwa " + numerals[f], (short)(256 + f)) ); } private void Save(string aFileName) { using (FileStream fs = new FileStream(aFileName, FileMode.Create, FileAccess.Write)) { foreach (Product p in Products) { fs.Write(BitConverter.GetBytes(p.Identifier), 0, Sizes[0]); fs.Write(CurrentEncoding.GetBytes(p.Symbol.PadRight(Sizes[1]).Substring(0, Sizes[1])), 0, Sizes[1]); fs.Write(CurrentEncoding.GetBytes(p.Name.PadRight(Sizes[2]).Substring(0, Sizes[2])), 0, Sizes[2]); fs.Write(BitConverter.GetBytes(p.Quantity), 0, Sizes[3]); } } } public void Generate() { Prepare(); Save(@"d:\out.bin"); } } }
Po uruchomieniu metody Generate(), na dysku powinien powstać identyczny plik, jak zamieszczony przeze mnie. Oczywiście, tak jak poprzednio, uczulam na zmianę ścieżki do folderu, w którym ma zostać zapisany plik ;).