6

As the title, really. I'm reading a SEQ file into memory, and need to know how big it is ahead of time. I know that I can get the size in blocks by parsing the directory, although it's ugly, but the disk system itself knows the size in bytes. How can I get it to tell me what it is?

2
  • 3
    Perhaps a stupid question, but do you really need to know this? What for? You've got the whole Commodore 64 to yourself, so no need to allocate memory. Just read as much as you can, and if the entire file does not fit into memory, process in chunks or throw an error, depending on what you're trying to do. – Michael Graf Dec 4 '20 at 18:48
  • I do really need it. – David Given Dec 4 '20 at 18:53
7

For a SEQ file, the directory holds the location of the first data block; each data block other than the last holds 254 bytes of data and the location of the next block, while the last block holds up to 254 bytes of data along with a count of how many are part of the file. Although the drive can tell when all of the bytes of a file have been read, there's no way it can determine the number of bytes within a file without examining every sector thereof. It's possible that code which uses the block-read (B-R) command to read the first two bytes of each block while ignoring the remainder might be faster than code which reads all of the data, but trying to determine a file's length is apt to be a slow operation in any case.

3
  • I thought that might be the case, but I was hoping there was a way around it. I assume this is also why seeking into a file is not supported --- the drive would have to go back to the first block and then look at each block in turn. (Of course, it could. As no data would be transferred it would be quick.) – David Given Dec 4 '20 at 19:00
  • 1
    @DavidGiven: It would probably be possible to write some machine code code for the 1541 which could read and transmit the first two bytes of every sector on a track in a single revolution. If that were done, the first random seek of a file would require about 250ms for each track that contained part of the file; if the C64 kept the information after reading it the first time, random fetches could be extremely fast if one had a routine that instead of being given a track and a sector number, would be given a track and a bitmap indicating what sectors were of interest, and would... – supercat Dec 4 '20 at 19:53
  • ...read and transmit the contents of the first sector it sees that qualifies. – supercat Dec 4 '20 at 19:55
4

It is a little bit involved but doable.

All but the last sector holds 254 bytes of data (2 being set aside for track/sector links to the next sector in the chain). The last sector has a 0 in the track link field and a number indicating much of the sector is actually used in the sector link field.

If you need the exact byte size of the file there is no way around crawling through the track/sector chain to get to the last sector. The first sector you get from the file's directory entry.

However, if you just need the "worst case" in number of sectors (fx to be able to bound a buffer), you can get the number of sectors used directly from the directory entry of the SEQ file, without following the chain. (Assuming the disk file has been closed properly, of course.)

Either way, you will have to read in and process the disk's directory structure. There is no DOS command or ROM routine to get the value directly; the disk system itself does not know the size in bytes.

2

Reading the directory (Filename "$") like described on page 23 of the manual is the way to go. Every other attempt would be even more 'ugly' If not slower.

Going thru the Directory is rather straight forward (the example can be streamlined) Entries are 32 bytes each with the file name in position 3..18 and total number of blocks in 28/29 (Low/High). Simply loop around reading them until the name matches and then pick the length in blocks.


Some Considerations:

  • How much will be wasted by taking the number of blocks times 254?

    Lets be serious, for a real world application, knowing the size in bytes, prior to reading it anyway, seams rather useless. After all, any knowledge would be only useful to determinate if it can be loaded at all. Taking the number of block times 254 will always end up with 0..253 bytes above real length length, but -and that's important for memory considerations - never below. 253 Bytes at 64 KiB, that is less than 0.4% Not sure if it's really worth to care about.

  • What will be the price to be payed when doing so?

    Using the simplified formula will end up refusing to load files that are exactly within 253 bytes of available space. So before investing much time in alternative routine, one should ask how many files will fall into this size range? Is there a worthwhile gain beside theoretical 100% fill?

    Adding an ability to 'fully' load may still end up with an unusable file - at least if extending isa legal operation :)

  • What is the price of byte exact size determination?

    Essentially doing so means reading all blocks to reach the last and then checking how many bytes are used there - which may or may not work as DOS does not really keep record about how far the last block is used at all.

Is There a Sensible Solution?

Well, the last paragraph already had it: Determination of the last block and it's filling level means reading the whole file, so why not

  • Deny any file with a size clearly above maximum

  • Read any below that threshold into memory

  • Break with an error (and reset any marker made so far) if it's larger than the memory available

Clear maximum is defined as the number of blocks that could store a file made up from the maximum memory available for that file or simply

(BytesAvailable/254)+1

The best part, this is a constant able to be calculated at compile time, so the whole checking at run time comes down to a 16 bit compare.

Performance wise this will perform

  • for loadable file like accessing the directory plus reading the file
  • for clearly non loadable files abort right after reading the directory
  • for the few files between max-size and (max-size mod 254 + 1) take as long as checking it's length by following the blockchain.

So instead of always spending the time to follow the chain, AND then spending that time again to load, every load is reduced to ... well, load time. Only the (asumable) small number of cases of being "just a little bigger than the memory but less than 254" will spend the whole time parsing the chain (which are exactly the cases were it's needed) before issueing a 'To big to load' error..

6
  • I appreciate the downvote. Except, it seems like simply trolling without any comment about why this may be wrong. – Raffzahn Dec 4 '20 at 18:49
  • 1
    I did not vote you down, but I suppose it was because OP already knew of the method you describe but doesn't want to use it. – OmarL Dec 4 '20 at 19:23
  • @OmarL Well, that wouldn't make it useless. After all, it is the most simple wayto get thatnumber. – Raffzahn Dec 4 '20 at 19:44
  • 1
    Well, I upvoted you. This is the only technique which doesn't require direct access to the filesystem structure, which means it'll work on non-Commodore disk systems. It doesn't give the byte size, sadly. Also, I vaguely remember seeing that the directory command supports wildcards? If so, I could just pass the drive the filename and it'd return exactly one entry, which would make parsing easier. – David Given Dec 4 '20 at 21:54
  • Since it's a sequential file, using the number of blocks times 254 as length will be at maximum 253 bytes off - and always on the safe side as never too small which is good when it's about reserving memory. In a real word application I would not care about the fraction at all and simply use block count times 256. --- For using wild cards, I'm not really sure how this should work. $ is already the symbolic file namefor the directory, not a pattern, or is it? – Raffzahn Dec 4 '20 at 22:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.