On Mar 10, 9:14 am, Tad McClellan <t...@augustmail.com> wrote:
> b...@stolenradio.com <b...@stolenradio.com> wrote:
> > On Mar 10, 1:05 am, b...@stolenradio.com wrote:
> >> BUT, if the file is incomplete when this action occurs, the above code
> >> sends only what's there when you open the file, and the download ends
> >> abruptly.
> > Nevermind guys, I figured out a way to make it work.
>
> The newsgroup is all about sharing.
>
> Care to share they way to make it work, or the root cause of the problem?
>
> > It always happens
> > that whenever I post a question on Usenet, I figure it out within the
> > hour. How bizarre.
>
> If it always happens, then it cannot also be bizarre. 
>
> You are not alone, that happens to everybody.
>
> --
> Tad McClellan SGML consulting
> t...@augustmail.com Perl programming
> Fort Worth, Texas
Ok, here's what I did. Hopefully my comments will explain it
sufficiently. The problem is that when a large file is being generated
on the fly and a download is requested from the server, the server
will only send the portion of the file that currently exists-- ie, if
the download rate is faster than the rate of generation, the download
will "catch up" and terminate because there is no file left, even
though you haven't reached the proper end of the file. The first
technique I tried was to start an infinite loop and check the file
size as packets are being sent.. if the file size is constant after a
large number of iterations (ie 20000 or so), then you can safely
assume that the file is no longer being created and you can finish the
download safely. This has overhead, however, and is not that
efficient. So the next method I tried, which works quite well, is to
append, at the very end, a string of characters designating the end of
the file (something like "###ENDOFFILE###" or similar). So we loop
through, reading $CHUNK_SIZE bytes at a time, and look for the
$END_OF_FILE text. If we find it at the end of our chunk, we omit the
end of file marker (as to not corrupt the file) and terminate the
script. Here's the main loop:
## open file, set up variables, etc. I omitted this part. You don't
really need to see it...
while (1) {
# where we are currently in the file. seek to there, and read into
$buffer
$pos = tell(FILE);
seek(FILE, $pos, 0);
read(FILE, $buffer, $CHUNK_SIZE);
# now, look one buffer size ahead. why? because if a buffer contains
at the end "###ENDO", we need to know if the next buffer will be
"FFILE###". it is very likely that a buffer will grab only part of our
end of file text
$pos2 = tell(FILE);
seek(FILE, $pos2, 0);
read(FILE, $buffer2, $CHUNK_SIZE);
# seek back to the original position so that in the next iteration,
we're in the right place
# this is NOT the best way to do this, and i will revise it. re-
reading a chunk is unnecessary here. i just got lazy
seek(FILE, $pos, 0);
read(FILE, $buffer, $CHUNK_SIZE);
#this conditional checks one buffer ahead. if the buffer ahead is less
than the length of the end of file text, we should check to see if it
contains our text. if it does, check the current buffer to see if it
has the other part of our text. if it does, print out the current
buffer, omitting our text, and quit the loop
if (length($buffer2) < $EOF_LEN) {
if ($buffer2 eq substr($END_OF_FILE, $EOF_LEN-length($buffer2)) ) {
if (substr($buffer, length($buffer)-($EOF_LEN-length($buffer2))) eq
substr($END_OF_FILE, 0, ($EOF_LEN-length($buffer2))) ) {
print substr($buffer, 0, length($buffer)-($EOF_LEN-
length($buffer2)));
last;
}
}
}
#assuming that the buffer ahead doesnt contain part of our end of
file, check to see if the current buffer has the whole end of file and
quit the loop. if so, print the buffer, omitting the end of file. if
not, just print the buffer.
if (substr($buffer, length($buffer)-$EOF_LEN) eq $END_OF_FILE) {
print substr($buffer, 0, length($buffer)-$EOF_LEN);
last;
} else {
print $buffer;
}
$count++;
}
This technique works quite well, and I've tested it many times without
issues. I hope it helps someone out there.
I also realize this may not be the best way to do it. If anyone has
other suggestions, throw em at me!