Τρίτη 14 Δεκεμβρίου 2021

Αναθεώρηση 47, Έκδοση 10 - Μεγάλα Αρχεία (>2GB)

Αναβαθμίστηκαν όλες οι εντολές αρχείων, που δουλεύουν με χειριστή αρχείου (file handler). Οι υπόλοιπες επειδή φέρνουν με μια εντολή στη μνήμη δεν μπορούν εκ των πραγμάτων να φορτώσουν πολύ την μνήμη (το μέγιστο είναι κοντά στα 2 GB). Όμως οι εντολές που αναβαθμίστηκαν μπορούν να διαβάζουν τμηματικά ένα αρχείο, μέσω χειριστή αρχείου και με χρήση του δρομέα που τώρα δεν έχει όριο τα 2GB. Πρακτικά δεν έχει όριο, μπορούμε να διαβάσουμε ένα αρχείο όσο μεγάλο και να είναι! Αν και φαινομενικά τα αρχεία που ανοίγουμε για Εισαγωγή, Εξαγωγή και Συμπλήρωση είναι Σειριακά, εντούτοις μπορούμε να αλλάζουμε κατά βούληση την θέση του δρομέα. Επίσης μπορούμε στο ίδιο αρχείο να ανοίξουμε και άλλους δρομείς (με νέους χειριστές αρχείων), ή αν θέλουμε να επιλέξουμε αποκλειστική "απασχόληση" και να μην επιτρέπουμε σε κανέναν να "ασχολείται" με το αρχείο μας.

Παλιότερα υπήρχε μέγιστος αριθμός 512 αρχεία, αλλά τώρα δεν υπάρχει αυτό, και υπάρχει εσωτερικά λίστα που ανακυκλώνει αριθμούς που "έπαιξαν" ή κατ' απαίτηση φτιάχνει νέο νούμερο. Ουσιαστικά σε αυτόν τον χώρο κρύβεται ο πραγματικός χειριστής αρχείου που δίνει το λειτουργικό σύστημα. Εμείς αντί να βλέπουμε τα παράξενα νούμερα του λειτουργικού, ξεκινάμε από το 1. 

Η εντολή Κλείσε (close) χωρίς παραμέτρους κλείνει όλα τα αρχεία άμεσα. Το ίδιο γίνεται και αν κλείσει η εφαρμογή ακόμα και μη αναμενώμενα (abnormal). Οπότε δεν "μένουν" κλειδωμένα αρχεία!

Η εντολή Άνοιξε (OPEN) μπορεί να ανοίξει αρχεία βάσει ANSI, ή WIDE (2bytes κάθε χαρακτήρας). Εξ ορισμού αν δεν δώσουμε το WIDE (ΕΥΡΕΙΑ) θα είναι το ANSI με το τρέχον τοπικό. Με τοπικό 1032 έχουμε ελληνικό ANSI (8bit ο χαρακτήρας). Όταν βάζουμε το ΕΛΛΗΝΙΚΑ τοπικό γυρνάει αυτόματα σε 1032. Με την εντολή Τοπικό 1032 το θέτουμε όταν θέλουμε. Η μεταβλητή ανάγνωσης Τοπικό δίνει τον τρέχον αριθμό.

Στο παράδειγμα παρακάτω, φτιάχνουμε μια Διάρθρωση μνήμης (BUFFER) με βασικό τύπο byte, με συνολικά 12MByte. Το alfa είναι δείκτης στη διάρθρωση, αν αλλάξουμε το δείκτη δίνοντας άλλη διάρθρωση η προηγούμενη χάνεται (δουλεύει με καταμέτρηση δεικτών, στο μηδέν διαγράφεται). Βέβαια μπορούμε να αλλάξουμε μέγεθος (όχι τύπο όμως). Η μνήμη που απασχολεί ενδέχεται να μετακινηθεί κατά την αλλαγή μεγέθους αλλά αυτό είναι πολύ σπάνιο. Για το χρήστη δεν έχει σημασία η μετακίνηση, όσο χρησιμοποιεί την μνήμη χωρίς να δίνει απόλυτες διευθύνσεις.

Η μεταβλητή R αλλάζει σε 1 ή 2 και έτσι επιλέγουμε "τυχαία" αν θα ανοίξουμε αρχείο κατά ANSI, ή κατά WIDE (οι βασικές εντολές γράφουν και διαβάζουν ως έχουν UTF16LE, αλλά στην ουσία δεν αποκωδικοποιούν, και αυτό που μετράει είναι ότι σημάδια όπως το κόμμα και η αλλαγή γραμμής είναι σε UTF16LE). Για το λόγο αυτό μπορούμε να γράψουμε ότι κωδικοποίηση θέλουμε, ειδικά αν βάζουμε και διαβάζουμε με διαρθρώσεις (αυτό σημαίνει διάβασμα/γράψιμο δυαδικών αρχείων,  και έτσι τα αρχεία της Μ2000 είναι και δυαδικά αν θέλουμε να είναι)

Στο παράδειγμα θα φτιάξουμε ένα αρχείο 12GB, και στο τέλος του θα γράψουμε κάτι που θα το διαβάσουμε αφού πρώτα κλείσουμε το αρχείο για εξαγωγή και το ανοίξουμε για εισαγωγή. Στο αρχείο τύπου Συμπλήρωση μπορούμε να εξάγουμε και να εισάγουμε μαζί! Υπάρχει και το αρχείο τύπου Πεδία, που φτιάχνουμε αρχεία με εγγραφές σταθερού πλάτους, και εκεί ο δρομέας λειτουργεί ανά εγγραφή, δηλαδή λέμε να γράψουμε στη 3η θέση εγγραφής. Το πλάτος έχει όριο τα 32768. Τα όρια θα μπορούσαν να μεγαλώσουν αλλά δεν έχουν νόημα να είναι μεγαλύτερα. Αν θέλουμε κάτι πολύπλοκο τότε μπορούμε να τα χειριστούμε με τα τρια πρώτα. Δηλαδή το αρχείο τύπου για Πεδία είναι απλά προσαρμοσμένο για ευκολία.

Στο πρόγραμμα έχει μπει ένα μπλοκ Δες ή Try που ελέγχει την περίπτωση σφάλματος και στην έξοδο κλείνει τα αρχεία με την Κλείσε (και να έχουν κλείσει ήδη όλα, δεν μας χαλάει μια Κλείσε).

Δείτε ότι ο χειριστής αρχείου έχει το # στην αρχή. Δεν το χρειάζεται σε όλες τις εντολές αλλά το βάζουμε, για να βλέπουμε τον κώδικα καλύτερα!

Εδώ έχουμε δώσει το exclusive δηλαδή το Αποκλειστικά, ώστε κανείς άλλος να μην πειράξει το αρχείο μας. Δεν είναι απαραίτητο, αλλά μπήκε για προβολή...

Δείτε ότι με την Seek() ή Μετάθεση() διαβάζουμε την μετάθεση (του δρομέα) από την αρχή. Ο πρώτος χαρακτήρας είναι στο 1.  Δεν υπάρχει πραγματικός δρομέας, αυτό το νούμερο είναι που χρησιμοποιεί το σύστημα αρχείων για τις εντολές που δίνουμε, πάνω στον χειριστή αρχείου, και το ενημερώνει. Δηλαδή αν γράψουμε δέκα bytes, θα τον αυξήσει κατά δέκα. Δεν γυρίζει πίσω αν δεν το "απαιτήσουμε" εμείς, με την Μετάθεση ή Seek (σαν εντολή και όχι σαν συνάρτηση). Για να γράψουμε στο τέλος του αρχείου, η Συμπλήρωση ξεκινάει από σημείο που δεν υπάρχει πραγματικό byte...αλλά θα το γράψουμε εμείς. Έτσι σε ένα κενό αρχείο ο δρομέας είναι στο 1. Ποτέ δεν είναι στο μηδέν (στο λειτουργικό είναι στο 0, αλλά στη Μ2000 το χειριζόμαστε από την μονάδα). Προσοχή, αν ανοίξουμε με Εξαγωγή ένα αρχείο και υπάρχει παλιό το σβήνουμε. 

Η εγγραφές() ή records() μας αναφέρει το μέγεθος του αρχείου. Το ίδιο και η Filelen() ή Αρχείου.Μήκος() αλλά η τελευταία δεν παίρνει χειριστή αρχείου αλλά παίρνει όνομα και ανοίγει το αρχείο μόνο για ανάγνωση χαρακτηριστικών (attributes). Η εγγραφές() αν έχουμε αρχείο για ΠΕΔΙΑ  (RANDOM) τότε δίνει τον αριθμό εγγραφών και όχι το μέγεθος σε bytes.

Γενικά οι εντολές/συναρτήσεις που επηρρεάστηκαν από την αλλαγή είναι οι παρακάτω:

  • OPEN, CLOSE, LINE INPUT, INPUT, PRINT, WRITE, SEEK, PUT, GET
  • SEEK(), RECORDS(), EOF()

Με την εντολή Βοήθεια διαβάζετε τι κάνει η κάθε μια.

Τέλος στην 47 έγιναν και μερικές βελτιώσεις (αθέατες, εκτός και αν διαβάζετε τον κώδικα στο GitHub).



buffer clear alfa as byte*12*1024*1024

const rJustNonProp=3
const columnwidth=14
// you can press Esc (automatic close all files, with last statement)
R=Random(1, 2)
Try ok {
If R=1 then
Open "giant1" for output exclusive as #f
else
Open "giant1" for wide output exclusive as #f
end if
For i=1 to 1024
m=Seek(#f)
put #f, alfa, m
Print Over $(rJustNonProp, columnwidth), m, str$(i/1024,"#.0%"), records(#f)
refresh
Next
Z=Seek(#f)
Print #f,"This is a big file"
Close #f
Print
Print filelen("giant1")
if R=1 then
Open "giant1" for input exclusive as #f
else
Open "giant1" for wide input exclusive as #f
end if
Print Records(#f)
seek #f, z
Line Input #f, what$
Close #f
Print what$
}
Close



Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.