📄 pasl1013.html
字号:
<p>Variable <tt>actual</tt> holds the number of bytes that is actually read from the
disk. Likewise, writing to disk is done through <tt>blockwrite</tt> :</p><pre>
:
rewrite(f,1);
:
:
count:=sizeof(buffer);
blockwrite(f,buffer,count,actual);
</pre><p>
You can even specify the number of bytes you want to read. Suppose you want
to read just 512 bytes from a file :</p><pre>
blockread(f,buffer,512,actual);
</pre><p>
Writing 512 bytes is just similar to reading. Now, how if the buffer is a
record ? Suppose I declare the record :</p><pre>
type
THeader = record
tag : string[4];
width, depth : word;
bitperpixel : byte;
end;
var
hdr : THeader;
</pre><p>
That kind of header is one example of reading picture file header. Usually,
after <tt>reset</tt>, programmer has to read the header to check validity. Reading
the header can be done by <tt>blockread</tt> :</p><pre>
blockread(f,hdr,sizeof(hdr),actual);
</pre><p>
The operator <tt>sizeof</tt> returns the number of bytes occupied by the operand or
parameter automatically (so that you don't have to count it manually). If
the file is good, the header is fully read. That can be checked by this :</p><pre>
if actual=sizeof(header) then { The file has a good header }
:
:
</pre><p>
But .... wait ! I saw somebody using untyped file with <tt>write</tt> and <tt>read</tt>.
Well, that kind of person treating typed file as untyped one. That causes
a LOT of pain. That's why I'm not going to teach it. But, if you insist,
you can write me.</p><p>That's all about untyped files.</p><h3>File Commands</h3>
<p>Now, we're going to discuss other file commands :</p><ol>
<li><tt>Rename</tt></li><li><tt>Erase</tt></li><li><tt>Getenv</tt></li>
<li><tt>FSearch, FExpand</tt> and <tt>FSplit</tt></li>
<li><tt>FindFirst</tt> and <tt>FindNext</tt></li>
<li><tt>UnpackTime</tt> and <tt>PackTime</tt></li>
<li><tt>GetFTime</tt> and <tt>SetFTime</tt></li>
<li><tt>GetFAttr</tt> and <tt>SetFAttr</tt></li>
<li><tt>DiskFree</tt> and <tt>DiskSize</tt></li></ol>
<p> Number 3 through 9 need <tt>DOS</tt> unit</p><p><tt>
Rename</tt>, just like its name is to rename files. You must assign the old file
name to a file variable, (the file is not necessarily be opened) then use <tt>
rename</tt> :</p><pre>
assign(f,oldname);
rename(f,newname);
</pre><p><tt>
Erase</tt>, is to erase files. You assign the file you want to erase, then erase
it. You may <b>NOT</b> open the file. If you've already opened it, close it first
before erasing !</p><pre>
assign(f,filename);
erase(f);
</pre><p>
You have used the <tt>crt</tt> unit so long and nothing else. Now, it's time to
corporate <tt>DOS</tt> unit, so you'll probably do this :</p><pre>
uses crt, dos;
</pre><p>
You need no files to add as <tt>crt</tt> and <tt>dos</tt> are both in <tt>SYSTEM.TPL. SYSTEM.TPL</tt>
is always loaded when Pascal starts. Why do we need <tt>DOS</tt> unit ? Well many of
file routines (that has been mentioned as number 3 thru 9) is in <tt>DOS</tt> unit.
Also, interrupt handling, system time and other handy things reside in it.
Let's cover the file-handling routines.</p><h4>Getenv</h4><p><tt>
Getenv</tt> fetches the environment string of DOS. Go to command prompt of DOS,
then type <tt>SET</tt> then press Enter. DOS displays all the environment string,
such as <tt>PATH, PROMPT</tt>, etc. This is example of how to get the <tt>PATH</tt>
contents (s is a string) :</p><pre>
s:=Getenv('PATH');
</pre><p>Getting <tt>PROMPT</tt> is similar : <tt>s:=Getenv('PROMPT');</tt></p>
<h4>FSearch</h4><p><tt>FSearch</tt> do searching files in a specified
directory. Suppose you want to search for <tt>FORMAT.COM</tt> in <tt>DOS</tt>
and <tt>WINDOWS</tt> directory :</p><hr><pre>
uses dos;
var
s : string;
begin
s:=FSearch('FORMAT.COM','C:\DOS;C:\WINDOWS');
if s='' then
writeln('FORMAT.COM not found')
else
writeln('FORMAT.COM found in ',s);
end.
</pre><hr><p>
When found, s returns complete path and filename, otherwise empty. You may
extend the directory list (the second parameter of <tt>FSearch</tt>) using semicolon
such as :</p><pre>
... FSearch( ... , 'C:\DOS;C:\WINDOWS;C:\SCAN;C:\TOOL');
</pre><p>
You may wonder that you can even search a file in the <tt>PATH</tt> environment
variable. Yes, you COULD ! Do it like this :</p><pre>
... FSearch( ... , getenv('PATH'));
</pre><h4>FExpand</h4><p><tt>FExpand</tt> expands a simple file name into a
full name (drive, full directory, and the file name itself). It is especially
useful when user inputs a relative directory, like this (s is a string) :</p><pre>
s:=FExpand('..\README');
</pre><p>S will be like this (for example) : '<tt>C:\PASCAL\LESSON.1\README</tt>'</p>
<h4>FSplit</h4><p>It is just contrary to <tt>FExpand</tt>, splits a fully qualified
name into directory, file name, and extension. Example :</p><pre>
var
s : string;
d : dirstr;
n : namestr;
e : extstr;
:
:
:
s:='C:\WINDOWS\WIN.INI';
fsplit(s,d,n,e); { d = 'C:\WINDOWS\', n = 'WIN', e = '.INI' }
</pre><p>Look at this program for better details.</p><hr><pre>
uses dos;
var
s : string;
d : dirstr;
n : namestr;
e : extstr;
begin
s:=FSearch('FORMAT.COM',getenv('PATH'));
if s='' then
begin
writeln('FORMAT.COM not found');
halt;
end;
writeln('FORMAT.COM found in ',s);
fsplit(s,d,n,e);
writeln(d,' ',n,' ',e);
end.
</pre><hr><h4>FindFirst and FindNext</h4><p><tt>FindFirst</tt> and <tt>FindNext</tt>
is used just like <tt>dir</tt> command in DOS. It uses the <tt>TSearchRec</tt> record
tag. The syntax of them :</p><pre>
findfirst(qualifier,attribute,searchrec);
findnext(searchrec);
</pre><p><tt>
qualifier</tt> can be '<tt>*.*</tt>' or '<tt>*.PAS</tt>' or any wildcard, just like the parameter
in <tt>dir</tt> command. The attribute can be :</p><center><table border=2>
<tr><th>Attribute</th><th>If you want to search for</th></tr>
<tr><td><center>ReadOnly</center></td><td><center>read-only files</center></td></tr>
<tr><td><center>Hidden</center></td><td><center>hidden files</center></td></tr>
<tr><td><center>SysFile</center></td><td><center>system files</center></td></tr>
<tr><td><center>VolumeID</center></td><td><center>disk volume label</center></td></tr>
<tr><td><center>Directory</center></td><td><center>directories</center></td></tr>
<tr><td><center>Archive</center></td><td><center>archive files</center></td></tr>
<tr><td><center>AnyFile</center></td><td><center>any files</center></td></tr>
</table></center><p><tt>TSearchrec</tt> is defined as follows :</p><pre>
type
TSearchRec = record
Fill: array[1..21] of Byte;
Attr: Byte;
Time: Longint;
Size: Longint;
Name: array[0..12] of Char;
end;
</pre><p>
Suppose I have the variable s declared as <tt>TSearchrec</tt>, and I'm using the
<tt>findfirst</tt> to search '<tt>*.EXE</tt>' with any attribute :</p><pre>
findfirst('*.EXE',AnyFile,s);
s.name holds the name
s.size holds the size in bytes
s.time holds the date and time when the file is created
s.attr holds the attribute
</pre><p>
You should never touch the fill field. It is classified. I personally don't
know what does it for, only folks in Microsoft did, perhaps.</p><p><tt>
FindFirst</tt> is used to INITIATE the search. <tt>FindNext</tt> is used to do the subsequent
search. You may repeat <tt>FindNext</tt> as many as you want to retrieve all
the filenames you desire. If there are no file names left, the variable
<tt>DosError</tt> is set to 18. For safety reason, you could repeat <tt>findnext</tt>
while the <tt>DosError</tt> remains 0, like this :</p><hr><pre>
uses dos;
var
s : TSearchrec;
q : string;
begin
write ('Enter qualifier to search = '); readln(q);
findfirst(q,AnyFile,s);
while DosError=0 do
begin
writeln(s.name);
findnext(s);
end;
end.
</pre><hr><p>
You may wonder how file date and time can be depicted as long integer. DOS
is actually packed them. So, after the call of <tt>findfirst</tt> and <tt>findnext</tt>, the
<tt>s.time</tt> is in a packed form. How to unpack them ? Use <tt>unpacktime</tt>.
The syntax is :</p><pre>
unpacktime(s.time,dt);
</pre><p><tt>
s.time</tt> is the packed form, <tt>dt</tt> is the unpacked form. <tt>Dt</tt> is a record of
<tt>DateTime</tt>, defined as follows :</p><pre>
type
DateTime = record
Year,Month,Day,Hour,
Min,Sec: Word;
end;
</pre><p>So, after <tt>unpacktime</tt> :<br>
<tt>dt.year</tt> holds the year<br>
<tt>dt.month</tt> holds the month, and so on (respectively).</p><p>
Look at the following example, that display the file with its size and its
date/time :</p><hr><pre>
uses dos;
var
dt : DateTime
s : TSearchrec;
q : string;
begin
write ('Enter qualifier to search = '); readln(q);
findfirst(q,AnyFile,s);
while DosError=0 do
begin
unpacktime(s.time,dt);
write (s.name :15, s.size:8,' ');
write (dt.month:2,'/',dt.day:2,'/',dt.year:4,' ');
writeln(dt.hour :2,':',dt.min:2,':',dt.sec);
findnext(s);
end;
end.
</pre><hr><p>
How about the attribute ? Is it packed too ? Not exactly. To detect each
attribute you must do this :</p><pre>
if s.attr and ReadOnly = ReadOnly then write('Read only ');
if s.attr and Hidden = Hidden then write('Hidden ');
if s.attr and SysFile = SysFile then write('System ');
:
:
and so on.
</pre><p>
You can do that detection routine to any attribute name shown above EXCEPT
for <tt>AnyFile</tt>.</p><p> How can I search for <tt>ReadOnly</tt> or <tt>Hidden</tt>
files only, but not archives and system files ? Do this at <tt>findfirst</tt> :</p><pre>
findfirst(q,ReadOnly or Hidden,s);
</pre><p>
You may combine the attribute with <tt>OR</tt>, not <tt>and</tt>. Also, you may not combine
<tt>AnyFile</tt> with others, because the combination would not take effect.</p>
<p>Actually, processing attributes is a bit-wise operation, which I haven't
taught you yet (later in lesson 2). But I made it as simple as possible, so
that you can understand.</p><h4>PackTime, GetFTime, and SetFTime</h4><p><tt>
UnpackTime</tt> has been described above. Now you may wonder how to <tt>PackTime.
PackTime</tt> is used like this :</p><pre>
packtime(dt,n);
</pre><p><tt>
dt</tt> is <tt>DateTime</tt> variable (unpacked time), <tt>n</tt> is a long integer holds packed
time. What does it for ? It's for setting the file time by <tt>setftime</tt> :</p><pre>
setftime(f,n);
</pre><p><tt>
F</tt> is any file variable (text, typed or untyped), n is the packed form of
date/time. Don't forget to assign f with a file name first.</p><p><tt>
GetFTime</tt> returns the date/time of the file :</p><pre>
getftime(f,n);
</pre><p><tt>
F</tt> and <tt>n</tt> is the same as in <tt>setftime</tt>. After <tt>getftime</tt>,
don't forget to unpack it first with <tt>unpacktime</tt>.</p>
<h4>GetFAttr and SetFAttr</h4><p>
Likewise, you can set or get a file's attribute using <tt>setfattr</tt> and
<tt>getfattr</tt>. Suppose f is any file variable (text, typed, or untyped), and
n is a word variable :</p><pre>
getfattr(f,n);
</pre><p>This will get the file attribute in n. Don't forget to associate f with a
file name first. Detecting the attribute is just the same as shown in <tt>findfirst</tt>
and <tt>findnext</tt>. Setting attribute takes the same syntax. Suppose
you want to set the file as hidden and read-only :</p><pre>
n:=ReadOnly or Hidden;
setfattr(f,n);
</pre><h4>DiskFree and DiskSize</h4><p><tt>
DiskFree</tt> returns the number of bytes free in a specified drive. <tt>DiskSize</tt>
returns the disk total size of a drive. Both take a byte as parameter :</p><pre>
n:=DiskFree(d); { d is a byte, n is a longint }
n:=DiskSize(d);
</pre><p>
d is the drive qualifier. D = 0 means that you want to search info in the
current drive, d = 1 for drive A, d = 2 for drive B, d = 3 for drive C and
so on. If n = -1, means that you have input an invalid drive.</p>
<h3>Directory commands</h3><p>We'll discuss these directory commands :</p><pre></pre>
<ol>
<li>
<pre>Chdir</pre>
</li><li>
<pre>Mkdir</pre>
</li><li>
<pre>Rmdir</pre>
</li><li>
<pre>Getdir</pre>
</li></ol><p><tt>
Chdir, Mkdir</tt>, and <tt>Rmdir</tt> is just the same as DOS command <tt>cd, md</tt>,
and <tt>rd</tt>. All of them takes a string parameter :</p><pre>
chdir('\DOS'); { same as cd\dos }
mkdir('\TEMP'); { same as md\temp }
rmdir('\TEMP'); { same as rd\temp }
</pre><p><tt>
Getdir</tt> is used to get the directory, just like you type <tt>cd</tt> in DOS prompt,
then press enter. The difference is that <tt>getdir</tt> can be used to get the current
directory of any drive, not just current drive as <tt>cd</tt> does. <tt>Getdir</tt>
syntax is like this :</p><pre>
getdir(d,s); { d is a byte, s is a string }
</pre><p>
d is the drive qualifier. D = 0 means that you want to search info in the
current drive, d = 1 for drive A, d = 2 for drive B, d = 3 for drive C and
so on. S will return the directory. If d is invalid s just say the root
directory. Suppose d:=23 (drive W) is invalid, s will return '<tt>W:\</tt>' as it
were a root directory.</p>
<p>Phew ! A tedious lesson has finished. That's all folks ! If you DO
understand what I've taught so long, then congratulations !
If you might want to continue the second lesson, wait for another issue !
So long !</p>
<hr><p><B><H3>Where to go ?</H3></B><p>
<A HREF="../news.html">Back to main page</A><BR>
<A HREF="pasles01.html">Back to Pascal Tutorial Lesson 1 contents</A><BR>
<a href="pasq1013.html">To the quiz</a><br>
<A HREF="pasl1012.html">Back to Chapter 13</A> about text files<BR>
<A HREF="pasles02.html">To Lesson 2</A><BR>
<A HREF="../mylink.html">My page of programming link</A><BR>
<A HREF="../faq.html">Contact me here</A>
<hr><P class="cpy">By : Roby Joehanes, © 1997, 2000</P>
</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -