Autor Wątek: Jak wykryć koniec pliku  (Przeczytany 4691 razy)

CzarusGG

  • *
  • Wiadomości: 2
Jak wykryć koniec pliku
« dnia: 2024.02.27, 01:45:27 »
Witam wszystkich!

ZX Spectrum 48K + Interface 1 + microdrives (2 kasetki) ZX BASIC

Mam problem z końcem pliku. Mam na kasetce microdrive plik tekstowy nieznanej długości. W języku BASIC otwieram strumień kanału "m" wskazujący na ten plik. Próbowałem z niego czytać za pomocą INPUT (każdorazowe wykonanie czyta jedną linię tekstu) oraz INKEY$ (każdorazowe wykonanie czyta tylko jeden znak). Czytam oczywiście w pętli. Ale nie jestem w stanie wykryć końca pliku i program zatrzymuje się z komunikatem End of file.

Czy ktoś wie, jak przeczytać zawartość pliku z microdrive do zmiennej tekstowej?

CzarusGG

  • *
  • Wiadomości: 2
Odp: Jak wykryć koniec pliku
« Odpowiedź #1 dnia: 2024.03.05, 10:02:07 »
OK. Zostawiam odpowiedź dla potomności, może komuś posłuży.

Odpowiedź brzmi nie da się!  :)

Aby dało się to zrobić musi być spełniony jeden z trzech warunków:

1. Znamy długość pliku i odczytujemy za pomocą INKEY$ tyle bajtów, ile jest w pliku.
2. Jako ostatni bajt mamy zapisany znacznik końca pliku i odczytujemy, do póki nie natrafimy na bajt o wartości tego znacznika. Dla plików tekstowych może to być np. CHR$ 255
3. Jako pierwsza zapisana informacja, to liczba stanowiąca ilość bajtów w pliku. Wtedy za pomocą INPUT odczytujemy długość i mamy spełniony warunek 1. Z tym, że taki plik, przestaje być plikiem tekstowym.

Zatem w moim przypadku, należało doprowadzić do sytuacji z punktu 2.

Skoro miałem już otworzony kanał do czytania (przykładowo 5) z pliku, to:
Otworzyłem kolejny kanał do zapisu w pliku tymczasowym:

OPEN# 6;"m";1;"temp"

Skopiowałem zawartość interesującego mnie pliku.

MOVE #5 TO #6

Dopisałem znacznik końca pliku.

PRINT #6;CHR$ 255;

Zamknąłem oba kanały.

CLOSE# 5: CLOSE# 6

Otworzyłem plik tymczasowy do czytania.

OPEN# 5;"m";1;"temp"

Teraz mogłem odczytać zawartość pliku czytając do póki nie napotkałem bajtu 255. Po przeczytaniu, zamykałem kanał 5 i usuwalem plik tymczasowy.

Poniżej cały podprogram odczytu pliku tekstowego do zmiennej. Podprogram zakłada, że w zmiennej f$ znajduje się nazwa pliku a w zmiennej DRV numer napędu. Zawartość pliku zwracana jest w zmiennej a$

1000 REM ReadFile (f$)
1010 OPEN# 5;"m";DRV;f$
1020 OPEN# 6;"m";DRV;"temp"
1030 MOVE #5 TO #6
1040 PRINT #6;CHR$ 255;
1050 CLOSE# 5
1060 CLOSE# 6
1070 OPEN# 5;"m";DRV;"temp"
1080 LET a$ = ""
1090 LET k$ = INKEY$#5
1100 IF k$ = CHR$ 255 THEN GOTO 1130
1110 LET a$ = a$ + k$
1120 GO TO 1090
1130 CLOSE# 5
1140 REMOVE "m";DRV;"temp"
1150 RETURN

tooloud

  • *****
  • Wiadomości: 3198
  • Miejsce pobytu:
    Warszawa
  • mydłem go!
Odp: Jak wykryć koniec pliku
« Odpowiedź #2 dnia: 2024.03.06, 10:17:59 »

Odpowiedź brzmi nie da się!  :)

yyyyy że jak?

1. Znamy długość pliku i odczytujemy za pomocą INKEY$ tyle bajtów, ile jest w pliku.

1. a co zawiera header pliku jak nie te informacje? Może kluczowe jest, że w BASICu nie wszystko można z komend BASICa, bo jak sama nazwa wskazuje jest to bardzo podstawowe czyli... BASIC :)

2. Metoda z odczytem sekwencyjnym "dopóki to nie EOF" jest prosta jak cep, z tym, że ma jedną wadę - może Ci zabraknąć pamięci, chyba, że to od razu buforujesz czy zapisujesz na inny otwarty do zapisu stream... Ja robiłem coś takiego mając podłączony emutor MD i normalne MD.
dużo sprzętu mało czasu.

matofesi

  • *****
  • Wiadomości: 2073
  • Miejsce pobytu:
    Toruń/Poland
Odp: Jak wykryć koniec pliku
« Odpowiedź #3 dnia: 2024.03.06, 11:31:30 »
@tooloud ad. 1 Mam wrażenie, że nagłówek plików sekwencyjnych nie zawiera długości...
ad. 2 Tu dla odmiany jak rozumiem problem polega na tym, że nie ma "dopóki EOF" tylko jak jesteś za "EOF" to BASIC wywala błąd.

tooloud

  • *****
  • Wiadomości: 3198
  • Miejsce pobytu:
    Warszawa
  • mydłem go!
Odp: Jak wykryć koniec pliku
« Odpowiedź #4 dnia: 2024.03.06, 11:47:45 »
a to nie jest tak, że dostęp do pliku jest sekwencyjny czyli czytamy go "bajtowo"? Nie ma czegoś takiego jak bajt po EOF, bo EOF przecież zamyka długość pliku. Czyli to jest null.
Header zależy od systemu plików czyli "DOS"a. MD/IF1 ma headery tylko są bardziej sektorowe. Czyli - da się to odczytać, ale nie z BASIC'a. Jak długi by nie był nasz program, to minimalnie i tak zajmie 512 bajtów danych zapisu + informacje sektorowe.

; Offset Length Name Contents
; ------------------------------
; 0 1 HDFLAG Value 1, to indicate header block
; 1 1 HDNUMB sector number (values 254 down to 1)
; 2 2 not used (and of undetermined value)
; 4 10 HDNAME microdrive cartridge name (blank padded)
; 14 1 HDCHK header checksum (of first 14 bytes)
;
; 15 1 RECFLG - bit 0: always 0 to indicate record block
; - bit 1: set for the EOF block
; - bit 2: reset for a PRINT file
; - bits 3-7: not used (value 0)
;
; 16 1 RECNUM data block sequence number (value starts at 0)
; 17 2 RECLEN data block length (<=512, LSB first)
; 19 10 RECNAM filename (blank padded)
; 29 1 DESCHK record descriptor checksum (of previous 14 bytes)
; 30 512 data block
; 542 1 DCHK data block checksum (of all 512 bytes of data
; block, even when not all bytes are used)
;
; 543 bytes altogether. Beware: .mdr files have an additional byte at the end.
; If it's !=0 this indicates "write protection".
dużo sprzętu mało czasu.

tooloud

  • *****
  • Wiadomości: 3198
  • Miejsce pobytu:
    Warszawa
  • mydłem go!
Odp: Jak wykryć koniec pliku
« Odpowiedź #5 dnia: 2024.03.06, 14:02:20 »
Cytuj
MD/IF1 ma headery tylko są bardziej sektorowe.
mikro korekta - nie sektorowe tylko blokowe.
dużo sprzętu mało czasu.

matofesi

  • *****
  • Wiadomości: 2073
  • Miejsce pobytu:
    Toruń/Poland
Odp: Jak wykryć koniec pliku
« Odpowiedź #6 dnia: 2024.03.06, 15:36:02 »
Nikt nie mówi, że się nie da. Postawiony problem to zrobienie tego z BASICa i tu odpowiedź jest taka, że się nie da.

W kilku miejscach w które zaglądałem sugestia jest taka, żeby problem rozwiązać tak jak to zrobił autor pytania. Można też - jak przeczytałem nie wdając się w szczegóły - grzebać po zmiennych systemowych i sprawdzać w którym miejscu bufora się znajdujemy, ale tam problem się pojawia wtedy jak plik będzie miał długość, która jest wielokrotnością 512 bajtów.

Ale ogólna odpowiedź jest taka, że z samego BASICa się nie da.

Phonex

  • *****
  • Wiadomości: 1265
  • Miejsce pobytu:
    Warszawa
Odp: Jak wykryć koniec pliku
« Odpowiedź #7 dnia: 2024.03.06, 17:38:45 »
Można też użyć obsługi błędów - chociażby z programu Supercode.
We wskazanej linii programu sprawdzić, czy błąd to "End of file" - jeśli tak to zakończyć odczyt i kontynuować program.
Nie bardzo eleganckie rozwiązanie, ale jak nie da się inaczej...

tooloud

  • *****
  • Wiadomości: 3198
  • Miejsce pobytu:
    Warszawa
  • mydłem go!
Odp: Jak wykryć koniec pliku
« Odpowiedź #8 dnia: 2024.03.06, 19:29:41 »
Panowie, nie chcę wyjść na marudę, ale poza plikami tekstowymi istnieje dość spora liczba zastosowań czytania plików binarnych, w których bajt o wartości 255 występuje na porządku dziennym (vide zawartość ekranu ZX Spectrum) a metoda "na wartość 255" no jakby... zadziała źle czyli jest to żadna metoda w sensie uniwersalności działania.

Nikt nie mówi, że się nie da. Postawiony problem to zrobienie tego z BASICa i tu odpowiedź jest taka, że się nie da.

Pokminiłbym na miejscu autora z wnioskami z tego tekstu, bo jest tam sporo info nt buforów, microdrive map etc. :
https://retrocomputing.stackexchange.com/questions/28072/using-sinclair-zx-microdrive-is-it-possible-to-random-access-a-text-file

IHMO da się to odczytać (długość bloku danych etc.), ale trzeba się trochę namęczyć, bo nie leży to w samym pliku programu a w bloku danych na MD. Ale odczytując mapę MD (a CAT też to musi robić) to już idąc dalej można się pobawić. IHMO nawet w BASICu da się zrobić do tego "obudowę" by to odczytać, ale będzie to już grubsze szycie :)
dużo sprzętu mało czasu.