我的任务是为 Unitech HT630,它运行专有的 DOS 操作系统,可以运行为 16 位 MS DOS 编译的可执行文件,但有一些限制。我正在使用 Digital Mars C/C++ 编译器,到目前为止它运行良好。
应用程序要求之一是数据文件必须是人类可读的纯文本,这意味着该文件可以导入到 Excel 中或通过记事本打开。我使用的可变长度记录格式与 CSV 非常相似,我已使用 C 标准库文件 I/O 函数成功实现了该格式。
保存记录时,我必须计算更新的记录是否大于或小于数据文件中当前记录的版本。如果更大,我首先将当前记录之后的所有记录向前移动,按在保存更新的记录之前计算出的大小差异。 EOF 由操作系统自动扩展以容纳额外的数据。如果更小,我将所有记录向后移动我计算的偏移量。这工作得很好,但是我发现没有办法修改 EOF 标记或文件大小来忽略最后一条记录结束后的数据。
大多数情况下,记录的大小会增加,因为数据收集程序在保存记录时会用数据填充一些空字段。仅当对现有条目进行更正时,或者在正常记录保存时,如果记录中的描述性数据比程序在内存中读取的数据长,记录的大小才会缩小。
在记录缩减的情况下,在文件中的最后一条记录之后,我留下了轮班前的所有数据。在“收缩记录保存”之后,我一直在文件中写入 EOF 分隔符,以表示记录的结尾位置,并填充剩余数据的空间,但随后我不再有一个干净的文件,直到“增长记录保存”将文件的大小扩展到填充空间的区域。 unistd.h
中的 truncate()
函数不起作用(我现在认为这仅适用于 *nix 风格?)。
我见过的一种建议解决方案涉及创建第二个文件并将您希望保存的所有数据写入该文件,然后删除原始文件。由于我只有 4MB 的磁盘空间可供使用,因此如果文件大小小于 2MB 减去我的程序可执行文件和配置文件的大小,则此方法有效,但否则会失败。当它投入生产时,用户最终会得到一个大小超过 2MB 的文件。
我查看了 Ralph Brown 的中断列表 和 IBM PC 汇编语言和编程,我似乎找不到任何可以更新文件大小或类似内容的内容。
在 DOS 中是否可以在不创建第二个文件的情况下减小文件的大小?
I've been tasked with writing a data collection program for a Unitech HT630, which runs a proprietary DOS operating system that can run executables compiled for 16-bit MS DOS with some restrictions. I'm using the Digital Mars C/C++ compiler, which is working well thus far.
One of the application requirements is that the data file must be human-readable plain text, meaning the file can be imported into Excel or opened by Notepad. I'm using a variable length record format much like CSV that I've successfully implemented using the C standard library file I/O functions.
When saving a record, I have to calculate whether the updated record is larger or smaller than the version of the record currently in the data file. If larger, I first shift all records immediately after the current record forward by the size difference calculated before saving the updated record. EOF is extended automatically by the OS to accommodate the extra data. If smaller, I shift all records backwards by my calculated offset. This is working well, however I have found no way to modify the EOF marker or file size to ignore the data after the end of the last record.
Most of the time records will grow in size because the data collection program will be filling some of the empty fields with data when saving a record. Records will only shrink in size when a correction is made on an existing entry, or on a normal record save if the descriptive data in the record is longer than what the program reads in memory.
In the situation of a shrinking record, after the last record in the file I'm left with whatever data was sitting there before the shift. I have been writing an EOF delimiter into the file after a "shrinking record save" to signal where the end of my records are and space-filling the remaining data, but then I no longer have a clean file until a "growing record save" extends the size of the file over the space-filled area. The truncate()
function in unistd.h
does not work (I'm now thinking this is for *nix flavors only?).
One proposed solution I've seen involves creating a second file and writing all the data you wish to save into that file, and then deleting the original. Since I only have 4MB worth of disk space to use, this works if the file size is less than 2MB minus the size of my program executable and configuration files, but would fail otherwise. It is very likely that when this goes into production, users would end up with a file exceeding 2MB in size.
I've looked at Ralph Brown's Interrupt List and the interrupt reference in IBM PC Assembly Language and Programming and I can't seem to find anything to update the file size or similar.
Is reducing a file's size without creating a second file even possible in DOS?
发布评论
评论(2)
要在 DOS 中减小文件大小,可以使用
int 21 (ax=4200h, bx=handle, cx:dx=offset)
查找截断点,并以零长度调用 write:int 21 (ax=4000h, bx=handle, cx=0
(意思是截断))To reduce a file's size in DOS, you seek to the point of truncation with
int 21 (ax=4200h, bx=handle, cx:dx=offset)
and call write with zero length:int 21 (ax=4000h, bx=handle, cx=0
(meaning truncate))作为调整记录大小时移动记录的替代方法,您可以使用“填充”字段来完成每个记录,将其填充到标准大小(例如,使用空格或类似内容)。
As an alternative to shifting the records around when resizing a record, you could finish each record with a "pad" field that pads it out to a standard size (eg with spaces or similar).