View previous topic :: View next topic |
Author |
Message |
smjg
Joined: 29 Sep 2004 Posts: 41
|
Posted: Fri Aug 12, 2005 10:06 am Post subject: [Bug] Deadly side effect of File.size() |
|
|
Using DMD 0.129, Using Windows 98SE.
It took me a while to isolate a bug. Both File.size() and File.flush() call f_fflush. On a file that is open for ReadOnly or ReadWrite, this has the side effect of moving the file pointer to the end of the file, if a read operation has taken place. I think what actually happens is that it clears out the underlying C FILE's internal buffer, hence anything in this buffer waiting to be read is lost.
Consequently, bytesAvailable becomes practically useless.
It's a shame the C library didn't provide separate functions to flush input and output. Meanwhile, I suppose we can ask ourselves: is there any point flushing here at all?- Do we need the value returned by size() to be up to date with pending write operations?
- If so, is there a better way of doing it? (I'm guessing making size() return the maximum of the actual size and pos() would do it, but haven't had time to test.)
Anyway, here's some code that shows the problem: Code: |
import indigo.io.file;
import indigo.io.datastream;
import std.stdio;
void main() {
auto File inputFile = new File("input.txt");
inputFile.open(IODevice.ReadOnly);
auto DataStream ds = new DataStream(inputFile);
char c;
while (!inputFile.atEnd) {
writefln("Available: ?d", inputFile.bytesAvailable());
ds >> c;
if (c == 0xFF) {
writefln("ff");
} else {
writefln("?02x: ?s", c, c);
}
}
}
| Output (with behaviour of atEnd() reverted to the original):
Available: 46
54: T
Available: 0
Error: Unexpected end of data stream.
Stewart. |
|
Back to top |
|
|
uwe
Joined: 05 Apr 2005 Posts: 34 Location: Stuttgart, Germany
|
Posted: Sat Aug 13, 2005 2:57 am Post subject: Good catch |
|
|
After reading File.size() i cannot even tell how in the world i got the idea that the file needs to be flushed there. Perhaps to get pending write operations done. Perhaps this is just useless and we could call fstat() instantly.
Or perhaps the code should be changed to something like this:
Code: |
long curPos = ftell(m_file);
long endPos = fseek(m_file, 0, SEEK_END);
fseek(m_file, curPos, SEEK_SET);
|
But i don't know if this will break pending/future read/write operations. Perhaps you could test that? That would be very nice.
Ciao
uwe |
|
Back to top |
|
|
smjg
Joined: 29 Sep 2004 Posts: 41
|
Posted: Sat Aug 13, 2005 3:54 am Post subject: Re: Good catch |
|
|
uwe wrote: | After reading File.size() i cannot even tell how in the world i got the idea that the file needs to be flushed there. Perhaps to get pending write operations done. Perhaps this is just useless and we could call fstat() instantly.
Or perhaps the code should be changed to something like this:
Code: | long curPos = ftell(m_file);
long endPos = fseek(m_file, 0, SEEK_END);
fseek(m_file, curPos, SEEK_SET);
|
But i don't know if this will break pending/future read/write operations. Perhaps you could test that? That would be very nice. |
fseek doesn't return the resulting position, only a success/failure value. You have to call ftell again to find out where it ended up.
I now have this similar code:
Code: | long curPos = f_ftell(m_file);
if (f_fseek(m_file, 0, fc_fseekend) != 0)
throw new IODeviceException("File position could not be set:\n" ~ f_errorstring()); // TODO i18n
long endPos = f_ftell(m_file);
if (f_fseek(m_file, curPos, fc_fseekset) != 0)
throw new IODeviceException("File position could not be set:\n" ~ f_errorstring()); // TODO i18n
return endPos; |
which seems to work at the moment. But there are problems with both ideas:- This won't work on files greater than 4GB, on platforms where the file API is only 32-bit. (Do such platforms allow such huge files?)
- The other solution (just call f_fstat) could lead to subtraction overflow in bytesAvailable if there are pending write operations.
But your idea gives me an idea for another (untested) way of implementing atEnd:
Code: | long curPos = f_ftell(m_file);
f_fseek(m_file, 0, fc_seekend);
if (f_ftell(m_file) == curPos) return true;
f_fseek(m_file, 0, fc_seekset);
return false; |
Stewart. |
|
Back to top |
|
|
uwe
Joined: 05 Apr 2005 Posts: 34 Location: Stuttgart, Germany
|
Posted: Sat Aug 13, 2005 11:45 pm Post subject: |
|
|
Please look into the current stewart.tar.gz. I have deleted the fileengine module, and File now uses the indigo.posix.* modules. If you make changes to the old file module, we have to redo them.
In the indigo.posix.* modules i have declared 64-bit access functions, which can transparently replace the older functions if compiled with version "Indigo_File64Bit". But you are right, the current Windows library shipping with D does not define these functions (ftell64 and fseek64). They are also missing from the stat() API. But the good news is that this is the reason i wrote the POSIX wrapper. All the OS dependence is concentrated into this subpackage, thus we can write our own Windows implementation as soon as we have time to :)
Your idea for atEnd() is nice. If the size() implementation works and does not interfere with reading/writing operations, this should do as well.
Ciao
uwe |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|