Pliki typowane w c#

0

W jaki sposób moge odczytac pliki typowane z Delphi w c#?

3

@neytro:

Gdyby pomyśleć o stworzeniu symetrycznej klasy/struktur w C#, jest to dość trudne, bo języki dzieli epoka.
W C# zmienna typu klasowego jest de facto tylko referencją, tablica jest referencją itd...
Potem się wdepnie na to, że bez trybów unsafe nie ma jak wczytać z pliku zlożonej struktury (nie ma, mówiąc pojeciami C, void *).

Chyba tylko "ręczne:" czytanie int32, 18 bajtów, pięc int16 itd
Nawet string jest złosliwy, bo jak myślisz Delphi to pewnie w kategoriach znak=8bitów, co już od wieków nie jest prawdą.

Mam nadziję, ze chcesz to tylko jednorazowo odczytać, aby przenieść dane i posłać stary program na śmietnik historii.
Plik typowany to bardzo archaiczna koncepcja, sięga operacji I/O z lat 1960tych, nie wiem jakie ma zalety, ale same wady

Jak masz aktywny projekt w Delhi, masz tam jakies senswone serializery JSON ? EKsport w podobnych formatach by był dość dobrze przenośny

5

@ZrobieDobrze: zrób dobrze i następnym razem nie wypowiadaj się na temat technologii, o której najwyraźniej nie wiesz zbyt wiele, ok? Bo jak na razie to Twój post rozsiewa absolutnie błędne twierdzenia, nie poparte żadnymi źródłami. Poza tym po raz kolejny widząc słowo Delphi masz jakieś dziwne i absolutnie błędne wyobrażenie na temat języka z sprzed 50 lat. No WTF!


Po pierwsze, ani Delphi, ani pliki typowane nie oddziela żadna epoka. Otóż pliki typowane, zarówno w starym Pascalu, jak i Delphi czy Free Pascalu, to jedynie cukier składniowy. To że język pozwala zapisać całą strukturę do pliku, nie oznacza, że ten plik będzie zawierał dane w jakimś kosmicznym formacie. W pliku znajdą się dane zgodne ze strukturą źródłową, ale nadal jest to zwykły plik binarny — dokładnie taki sam można w C stworzyć po prostu w pętli zapisując całe bloki pamięci kolejnych struktur np. z tablicy. W innych językach wysokiego poziomu, nawet jeśli nie można wczytać całej struktury naraz (w co szczerze wątpię), można otworzyć plik i czytać dane np. za pomocą strumieni, tak jak z każdego innego pliku binarnego/amorficznego, czyli pakiet po pakiecie, a każdy pakiet pole po polu.

Po drugie, ciągów znaków nigdy nie zapsuje się do plików binarnych po prostu zapisując obiekt ciągu. Nigdy się tego nie robi, bo długie stringi o dynamicznej długości są referencjami, a więc pointerami, w dodatku napchanymi metadanymi (fizyczna długość w bajtach, refcount, codepage itd. itp.). Zawsze i w każdym jezyku należy dla każdego ciągu zapisać kilka danych w kilku krokach, przy czym obowiązkiem jest zapisanie najpierw długości w bajtach, a następnie bufora ciągu (pozostałe dane są opcjonalne).

Po trzecie, Pascale mają na tym polu przewagę, bo posiadają ciągi krótkie (typ ShortString) oraz ciągi o dowolnej limitowanej długości (np. String[10], maksymalnie do 255 znaków), które mogą być zapisywane bezpośrednio do pliku (jako jeden ciągły blok bajtów) — bajt zerowy zawiera długość w bajtach, kolejne to zawartość ciągu. Można bez problemu zapisać bezpośrednio cały blok takiego stringa, a później np. w C go wczytać — najpierw pobierając bajt z długością, potem cały blok zawartości ciągu. Podobnie w przypadku dowolnego innego języka, który obsługuje pliki binarne (czyli praktycznie każdego, bo pliki binarne to nic nadzwyczajnego).

Po czwarte, Delphi nie było ograniczone do ciągów wykorzystujących 8-bitowe code pointy, a więc do standardów ASCII i ANSI. Wsparcie Unicode istniało w formie typów WideChar i WideString, które mogły być wykorzystywane np. w funkcjach systemowych (z Win32 API). Ciągi do roku ~2005 domyślnie były AnsiStringami, ale wsparcie Unicode'u było.

Po piąte, nadal używa się ciągów znaków 8-bitowych, np. we Free Pascalu, do reprezentacji ciągów znaków kodowanych w UTF-8 (wewnętrznie jako standardowych typów AnsiString). Nie ma więc żadnego powodu, aby widząc AnsiString czy ”8-bitów na znak”, uznawać implementację za przestarzałą.

2

@neytro: dokładnie tak samo jak je zapisałeś w delphi.
Wrzuć tu kod rekordu z Delphi to dopasujemy do niego strukturę w c#
a tu przykłady jak się do tego zabrać https://www.google.com/search?client=opera&q=c%23+read+struct+from+file

0
abrakadaber napisał(a):

@neytro: dokładnie tak samo jak je zapisałeś w delphi.
Wrzuć tu kod rekordu z Delphi to dopasujemy do niego strukturę w c#
a tu przykłady jak się do tego zabrać https://www.google.com/search?client=opera&q=c%23+read+struct+from+file

No niezbyt, możesz to zrobić używając unsafe kodu i marshallingu, ale nie ma w pełni "bezpiecznego" (safe) sposobu żeby to zrobić. Jest BinaryFormatter ale on nie pracuje na gołych danych takich jak w plikach typowanych tylko dodają swoje nagłówki określające typy itp. W dodatku nie jest bezpieczny (secure) i odradza się jego używania. Sama dokumentacja mówi:

BinaryFormatter is insecure and can't be made secure. For more information, see the BinaryFormatter security guide.

Chodzi o to że zserializowane dane zawierają informacje o typach, te można podmienić na podklasy i w ostateczności doprowadzić nawet do wykonania kodu przy deserializacji. Można więc od razu zapomnieć o jego istnieniu i używaniu jeśli dane pochodzą z zewnątrz.
Jedynym bezpiecznym i bezpiecznym (safe & secure) sposobem jest przeczytanie pliku jako strumenia bajtów (BinaryReader) i ręczny mapping przy użyciu .ReadInt16() / .ReadInt32(), .ReadBoolean() itp. Największy problem będzie ze stringami, zwłaszcza null terminated lub w innym kodowaniu znaków.

Najłatwiejszy chyba sposób to zrobienie jednorazowego toola przy użyciu unsafe code'u - wtedy możesz zdefiniować zwykłe struktury podobne do tych z delphi i przerzucić format pliku na jakiś bardziej elastyczny i współczesny lub jeszcze lepiej zapisać dane do bazy danych (choćby sqlite).

Ewentualnie poszukaj jakiejś paczki nugetowej lub gotowego kodu na githubie do tego, na szybko nie znalazłem, ale myślę że coś się powinno znaleźć. W dzisiejszych czasach powstałby do tego pewnie source generator, ale problem nie jest współczesny.

0

Jest coś takiego jak BinaryReader i nigdzie nie jest napisane, aby obsługiwał jakiekolwiek metadane. To powoduje, że bez problemu można wczytywać dane z dowolnego pliku binarnego, stworzonego w dowolnym języku programowania — o ile zna się budowę tego pliku.

I np. w opisie metody BinaryReader.ReadInt32 jest wyraźnie napisane:

Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.

czyli że odczytane zostają 4 bajty i o tyle bajtów przesuwany jest wskaźnik w pliku.

Gdyby metody odczytujące dane wymagały metadanych, to przy odczycie danych wskaźnik nie byłby przesuwany o ilość bajtów które się żąda, a o SizeOf(Data) + SizeOf(Metadata) (w pseudojęzyku ilustrując), co jak widać nie jest prawdą.

0

a ja mam dwa pytania?

  1. czy chcesz po prostu odczytać dane z tych plików (pliku) i zaimportować do swojej aplikacji aby zastąpić rozwiązanie Delphi które aktualnie jest używane?
  2. a może chcesz na bieżąco czytać dane ze swojej aplikacji a tworzone będą nadal w "starej"?

Domyślam się że nie masz źródła aplikacji napisanej w Delphi ani też możliwości załatwienia eksportu tych danych do jakiegoś otwartego formatu ale jednak znasz ich strukturę?
Biorąc pod uwagę że takie pliki najczęściej tworzone są danymi które są jakimiś rekordami, może lepiej byłoby napisać aplikację w Delphi aby potrafiła odczytać te dane? Nie będzie problemu z typami danych ani kodowaniem. Gdy taki program napiszesz, bez problemu możesz do niego dopisać moduł eksportujący dane?

Jeszcze większe miałoby to znaczenie gdybyś na bieżąco chciał korzystać z tych danych. Aplikacja w Delphi byłaby takim hubem dla danych (w ostateczności zamiast aplikacji możesz napisać w delphi bibliotekę dll która będzie udostępniała ci te dane).

1 użytkowników online, w tym zalogowanych: 0, gości: 1