[comp.sys.atari.st] FILE I/O

jdn@homxc.UUCP (J.NAGY) (11/05/87)

The functions Fseek, fseek (and Fread, fread, Fwrite, fwrite, etc.)
seem to perform essentially equivalent functions.  To do simple file
i/o, I could use the capital F's or the small f's to do essentially
the same things.  Is there a prefered choice?  How do you choose?

My inclination is to use the small f's since I'll end up with code
which is easier to port to a unix environment.  Is there something subtle
going on here that I'm missing?

Thanks,

Jonathan Nagy
{ihnp4|allegra|harvard}!homxc!jdn
(201) 615-4349

ws1i+@andrew.cmu.edu (William Manchester Shubert) (11/09/87)

	As far as I can tell, it's up to you.  The "F" functions are probably
a bit faster, since they're just #defines that jump you right into the system
stuff; the "f" functions, while it is true that they're more compatible with
other environments, will probably be a bit slower since they go through some
translation routines first.  However, any extra time that the "f" functions
take will probably be so small (as in less than a hundred machine
instructions) that it won't matter (especially since the functions take
forever, anyway, since they all need to do disk I/O).  Anyway, there's your
difference.

braner@batcomputer.tn.cornell.edu (braner) (11/09/87)

[]

The GEMDOS Fread(), etc are more similar to the UNIX read(), etc,
NOT fread(), etc.  The raw GEMDOS functions are faster (due to
no buffering) but you should set up your own buffering.  (I found out
that a 9Kbyte buffer is good enough for almost-maximum floppy-disk
performance.)  If you want to write code so that it is easy to port
to UNIX and such, write read(), etc calls in the UNIX syntax, and
set up a bunch of routines with those names that simply translate
to the GEMDOS calls.   (BEWARE of int-vs-long problems!)

- Moshe Bran.]6

stuart@cs.rochester.edu (Stuart Friedberg) (11/09/87)

In article <2023@homxc.UUCP>, jdn@homxc.UUCP (J.NAGY) writes:
> The functions Fseek, fseek (and Fread, fread, Fwrite, fwrite, etc.)
> seem to perform essentially equivalent functions.
> Is there a prefered choice?  How do you choose?

The capital F functions are GEMDOS functions, similar but not
identical to UNIX system calls.  That is, Fread is similar to read,
Fseek is similar to lseek.

The little f functions are STDIO library functions, identical to
standard IO library functions everywhere.  (Or at least as close
as MW could make them.)  That is, fread under MWC on an Atari does
exactly what fread under UNIX on a VAX does.

If you want to write portable code, I suggest using the little f
functions from the standard IO library.  They're standard. :-)

If you need more control over exactly what it going on, use the
capital F functions from GEMDOS.  If you port something that close
to the machine, changing a function name from "Fssek" to "lseek" will
be the least of your problems.

Stu Friedberg  {ames,cmcl2,rutgers}!rochester!stuart  stuart@cs.rochester.edu

jdn@homxc.UUCP (11/09/87)

In article <2862@batcomputer.tn.cornell.edu>, braner@batcomputer.tn.cornell.edu (braner) writes:
> 
> The raw GEMDOS functions are faster (due to
> no buffering) but you should set up your own buffering.  

I don't quite understand this.  If I have to do my own buffering with
Fread, while fread does the buffering for me, then the fread call
appears easier to use.  And since the application has to buffer Fread
calls itself, any speed advantage of Fread (due to no buffering!) is
negated. So I can see no advantage to the Fread.

From your posting, I gather that you use the capital F's rather than the
small f's.  Moshe, could you please clarify this.


Jonathan Nagy
{ihnp4|allegra|harvard}!homxc!jdn
(201) 615-4349

apratt@atari.UUCP (Allan Pratt) (11/10/87)

in article <2023@homxc.UUCP>, jdn@homxc.UUCP (J.NAGY) says:
> 
> The functions Fseek, fseek (and Fread, fread, Fwrite, fwrite, etc.)
> seem to perform essentially equivalent functions.  To do simple file
> i/o, I could use the capital F's or the small f's to do essentially
> the same things.  Is there a prefered choice?  How do you choose?

The cap-F functions are OS calls, and the little-f functions are library
calls.  If you use little-f functions, you are bound to the vagaries
of your library.  In the case of Alcyon's GEMLIB, these vagaries
are actually debilitating bugs.  I don't use GEMLIB's little-f functions.

Among the pitfalls you can encounter are: newline translation and redirection
problems.  The cap-F functions all treat files as bags o' bits, with no
translation or anything.  Many libraries translate \r\n in a file into
\n alone; this takes longer and may not be what you want.

Also note that the parameters are not in the same order:  the guy who
wrote GEMDOS got it wrong relative to UNIX.

============================================
Opinions expressed above do not necessarily	-- Allan Pratt, Atari Corp.
reflect those of Atari Corp. or anyone else.	  ...ames!atari!apratt

braner@batcomputer.tn.cornell.edu (braner) (11/10/87)

[oops...]

What I meant was that reading a big block is a lot faster than reading
char by char using fgetc() and such (getc, getchar).  If you are going
to read a big block you might as well use low level calls (Fread) for
maximum speed.  But I guess you _could_ use fread() as supplied by your
compiler vendor.  Just hope they implemented it efficiently...

One more warning: if you use a compiler with 16-bit int's (as it should be
on a 68000!) you are limited as to the amounts you can specify in the
count arguments for fread(), malloc(), etc.  You _have_ to descend to
the raw OS calls if you need to use a long count.

- Moshe Braner

dillon@CORY.BERKELEY.EDU (Matt Dillon) (11/10/87)

> The raw GEMDOS functions are faster (due to
> no buffering) but you should set up your own buffering.  

	Amusing.  If the raw GEMDOS functions are faster due to not
buffering, why would you want to add buffering?  

	In fact, the raw GEMDOS functions are only faster if you do huge
read/write requests, and even then the difference shouldn't be noticeable.
Try reading a character at a time.... or a line at a time... this is why
buffering exists.

>I don't quite understand this.  If I have to do my own buffering with
>Fread, while fread does the buffering for me, then the fread call
>appears easier to use.  And since the application has to buffer Fread
>calls itself, any speed advantage of Fread (due to no buffering!) is
>negated. So I can see no advantage to the Fread.

	fread() USES Fread().  Using fread() means that more code is imported
from the C link library (or whatever languge you are using).  Fread() is a 
direct OS call.  So if you are an application written in straight assembly,
fread() isn't available to you without setting up the proper enviroment... 
done automatically by the startup code in, say, a C link library.  fread()
would be a function IN that library.  Or, perhaps, you want to save space
and make the executable as small as possible; in that case, you wouldn't 
want to include the X Kbytes of code that stdio takes.

					-Matt

minow@decvax.UUCP (Martin Minow) (11/11/87)

In article <2023@homxc.UUCP> jdn@homxc.UUCP (J.NAGY) asks about the
difference between Fseek and fseek (etc.), noting that they look
quite similar.

The "lower-case" functions match the C stdio library routines.
The "Upper-case" functions are direct calls to the operating system.
(As such, they are closer to lseek(), open(), etc.)  As noted, the
lower-case functions are generally preferable for portability.

The Upper-case functions are the only ones that can be used in a desk
accessory (they don't expand memory).  They are *much* harder to use.
As a public-service, I'm including a small open a file and read a byte
routine.  The code is made ugly as the operating system doesn't seem
to have a notion of "end of file."  (It's extracted from a longer program
and untested as such, so use it as a model only.)

Martin Minow
decvax!minow

-----
#include <osbind.h>
#include <stat.h>

#define FileBufferSize	512
typedef struct {
    int		handle;
    long	filesize;
    long	offset;
    char	*bp;
    char	*ep;
    char	buffer[FileBufferSize];
} FileInfo;

#define FileTell(fid)	((fid)->offset)

#define strchr	index			/* Brain-damaged Software Dev.	*/

FileInfo	InFile;
char		filename[64];		/* Stores file name for open	*/


typeout(infile)
char		*infile;
{
	register int		c;

	if (strchr(infile, ':') == NULL
	 && strchr(infile, '\\') == NULL) {
	    filename[0] = Dgetdrv() + 'a';
	    filename[1] = ':';
	    filename[2] = EOS;
	    Dgetpath(&filename[2], 0);	/* Must use "default" here	*/
	    strcat(filename, "\\");
	    strcat(filename, infile);
	}
	else {
	    strcpy(filename, infile);	/* User specified drive name	*/
	}
	if (FileOpen(&InFile, filename, 0) < 0) {
	    Cconws("Can't open the file\r\n");
	    Pterm(1);
	}
	while ((c = FileGetc(&InFile)) != EOF)
	    Cconout(c);
	Fclose(Infile.handle);
	Pterm(0);
}

int
FileOpen(fid, filename, mode)
register FileInfo	*fid;		/* Store stuff here		*/
char			*filename;	/* Fully-qualified file name	*/
int			mode;		/* Open mode			*/
{
	DMABUFFER	stupid;		/* Needed to get file size	*/
	int		status;

	Fsetdta(&stupid);
	if ((status = Fsfirst(filename, 0)) < 0)
	    return (status);
	fid->filesize = stupid.d_fsize;
	fid->offset = 0;
	fid->bp = fid->ep = NULL;
	fid->handle = Fopen(filename, mode);
	return (fid->handle);
}

int
FileGetc(fid)
register FileInfo	*fid;
{
	register long		readsize;
	register int		result;

	if (fid->offset >= fid->filesize)
	    return (EOF);
	while (fid->bp >= fid->ep) {
	    readsize = fid->filesize - fid->offset;
	    if (readsize > FileBufferSize)
		readsize = FileBufferSize;
	    if ((readsize = Fread(fid->handle, readsize, fid->buffer)) <= 0)
		return (EOF);
	    fid->bp = &fid->buffer[0];
	    fid->ep = &fid->buffer[readsize];
	}
	fid->offset++;
	return(*fid->bp++ & 0xFF);
}

preston@felix.UUCP (Preston Bannister) (11/11/87)

In article <183@decvax.UUCP> minow@decvax.UUCP (Martin Minow) writes:
>In article <2023@homxc.UUCP> jdn@homxc.UUCP (J.NAGY) asks about the
>difference between Fseek and fseek (etc.), noting that they look
>quite similar.
>
>The Upper-case functions ...  are *much* harder to use.
[ text of example deleted ]

There is a much simpler way to find the length of a file.  You simply
do an Fseek to the end of the file.  This means of getting the length
of a file is also usable with Unix and MSDOS (if not always necessary).
(I'm doing this from memory):

void
Example (filename)
  char *filename;
{
  int f, length;
  f = Fopen(name,0);
  if (f > 0)
  {
    length = Fseek(f,0,2);	/* seek to end of file */
    Fseek(f,0,0);		/* seek back to beginning of file */
    /* we now know the size of the file */
    ProcessFile(f,length);	/* for instance */
    Fclose(f);
  }
}
--
Preston L. Bannister
USENET	   :	ucbvax!trwrb!felix!preston
BIX	   :	plb
CompuServe :	71350,3505
GEnie      :	p.bannister

c9c-eh@dorothy.Berkeley.EDU (Warner Young (WHY)) (11/13/87)

In article <2064@homxc.UUCP> jdn@homxc.UUCP (J.NAGY) writes:
>In article <2862@batcomputer.tn.cornell.edu>, braner@batcomputer.tn.cornell.edu (braner) writes:
>> 
>> The raw GEMDOS functions are faster (due to
>> no buffering) but you should set up your own buffering.  
>
>I don't quite understand this.  If I have to do my own buffering with
>Fread, while fread does the buffering for me, then the fread call
>appears easier to use.  And since the application has to buffer Fread
>calls itself, any speed advantage of Fread (due to no buffering!) is
>negated. So I can see no advantage to the Fread.
>

	I wondered about this also, for some time.  Then I decided to
	test it out.  A friend and I each wrote the same program, but
	I used the capital F calls, and he the lower case f calls.  I
	even put more bells and whistles into my program, and the speed
	is significantly higher, even accounting for the fact that I
	have to do my own buffering and managing.

	8K to 16K are the best speeds, to get the most out of your
	floppies.  I haven't done any tests to see how much difference
	buffer size makes on a hard disk (my Supra died!).

						\          /
Disclaimer:  I'm not associated			 \  /\    /arner
	with the latest revision		  \/  \__/
	of SANITY.				         |oung
						     \___|
Last known address: c9c-eh@dorothy.Berkeley.EDU
			or
		    ucbvax!dorothy!c9c-eh

singer@XN.LL.MIT.EDU (Matthew R. Singer) (11/13/87)

In article <12361@felix.UUCP>, preston@felix.UUCP (Preston Bannister) writes:
> 
> There is a much simpler way to find the length of a file.  You simply
> do an Fseek to the end of the file.  This means of getting the length
> of a file is also usable with Unix and MSDOS (if not always necessary).
> (I'm doing this from memory):
> 
> void
> Example (filename)
>   char *filename;
> {
>   int f, length;
>   f = Fopen(name,0);
>   if (f > 0)
>   {
>     length = Fseek(f,0,2);	/* seek to end of file */
>     Fseek(f,0,0);		/* seek back to beginning of file */
>     /* we now know the size of the file */
>     ProcessFile(f,length);	/* for instance */
>     Fclose(f);
>   }
> }
> --
> Preston L. Bannister

This is a VERY slow way to do it. Especially on LARGE files where
the seek is worse than the open.

Why not just use Fsfirst and read the file size out of the DTA?
This works on both Gemdos and MSdos.

Matt Singer

rwa@auvax.UUCP (Ross Alexander) (11/14/87)

Preston Bannister and Matt talk about (to my mind, d*mned baroque) ways
to get the size of a file in the context of the MWC programming environment.

Try stat().  That's what it's for, among other things.  It also works on
Un*x, which to my mind is a far nicer thing to have compatability with than
mushdos.  One trap you are ignoring is: what if the file is a directory?
Nice to have it's attributes, perhaps?

hmmpf grump mutter. (its 5 am and my code *still* doesn't work.  Someone
must pay, and as luck would have it, you two win...)

Ross Alexander @ Athabasca University

preston@felix.UUCP (Preston Bannister) (11/15/87)

>> There is a much simpler way to find the length of a file.  You simply
>> do an Fseek to the end of the file.  This means of getting the length
>> of a file is also usable with Unix and MSDOS (if not always necessary).
>> (I'm doing this from memory):

>This is a VERY slow way to do it. Especially on LARGE files where
>the seek is worse than the open.

The Fseek operation doesn't actually cause any physical disk activity.
All the file system has to do implement Fseek is change it's internal
'position in file' number.  (Assuming that the file system
implementation isn't incredibly brain-damaged :-)

--
Preston L. Bannister
USENET	   :	ucbvax!trwrb!felix!preston
BIX	   :	plb
CompuServe :	71350,3505
GEnie      :	p.bannister