can't open in use file even for reading

I'm using the following function to mimic the tail command in unix.   It needs to open a file and read from it.  As you can see I'm only opening it in readonly mode but I still get the error that I cannot access the file.   Can anyone suggest an alternate method to accomplish this task?  

function tform1.Tail(FileName:string; Position:Integer):string;
var
  S: TStream;
  C: Char;
  L: Integer;
begin
  S := TFileStream.Create(FileName, fmOpenRead ,fmShareDenyNone);
  try
    S.Seek(Position, soBeginning);
    L := S.Size-Position;
    SetLength(Result, L);
    S.Read(Result[1], L);
  finally
    S.Free;
  end;
end;


Thanks!
LVL 1
hibbidijiAsked:
Who is Participating?
 
kretzschmarCommented:
it could be that another process did open this file exclusive
-> no chance to read it by your process
0
 
hibbidijiAuthor Commented:
Hiya Michael!
How about workarounds?   Executing a file copy then reading that temp file?   Anything else you can think of?
Thanks!
0
 
kretzschmarCommented:
>Executing a file copy then reading that temp file?  
if you can copy it, then you should it also read it.

do a test, then we look further

btw. a similar q was here one/two years ago,
i will search it, maybe this solution is useable for u

meikl ;-)
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
hibbidijiAuthor Commented:
When using a shell copy function I can indeed copy the file, though my own internal functions seem to be keeping ahold of the file  - I'm sure I can chase that down though.  Here is my copy file function using shellapi
function scShellCopyFile(FormHandle : THandle; StrFrom, StrTo : string; BlnSilent : Boolean = False) : Boolean;
var
  F : TShFileOpStruct;
begin
  F.Wnd:=FormHandle;
  F.wFunc:=FO_COPY;
  F.pFrom:=PChar(StrFrom+#0);
  F.pTo:=PChar(StrTo+#0);
  F.fFlags := FOF_ALLOWUNDO or FOF_RENAMEONCOLLISION;
  if BlnSilent then
    F.fFlags := F.fFlags or FOF_SILENT;
  if ShFileOperation(F) <> 0 then
    result:=False
  else
    result:=True;
end;

0
 
kretzschmarCommented:
hmm, the other solution is exactly what you posted,
guess you got it from here :-))


can you copy the file?

meikl ;-)
0
 
hibbidijiAuthor Commented:
I found that I had an open filemap handle on the file and killed it - this let go of my file so I could mess about with the temp file.   I suppose the only question would be should the shell be able to copy a file yet delphi not be able to read it (readonly).  I have my solution to a point - it will work though it's a little roundabout.   Any other ideas do you think?
0
 
hibbidijiAuthor Commented:
Sorry for the cross post-  looks like this is the solution.   Thanks for pointing me at the untouchable file and have a great day.
0
 
kretzschmarCommented:
ok, didn't see your last comment before my last post

so it should be possible to read from the file

this kind of streamcreation i never used (seems to be a overloaded method)
  S := TFileStream.Create(FileName, fmOpenRead ,fmShareDenyNone);

maybe it makes a differentce if u use
  S := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);

a copy and then a read makes not much sense, if the file is huge,
but of course on smaller files it may be a workaround

meikl ;-)
0
 
hibbidijiAuthor Commented:
trying your solution now - will request a change if we get it fixed with your method
0
 
kretzschmarCommented:
hups,

we are both really active at same time.
well, it is solved for you,
then i could paq this q and refund your points
with my role as Page Editor

meikl ;-)
0
 
kretzschmarCommented:
puh, seems i am too slow :-))
0
 
hibbidijiAuthor Commented:
I'll see how my read goes with your code - this might be really helpful if it does help and I'm not worried on the points :)  I'll let you know what I come up with.  it's definitely different with the OR.  it appears to be freezing now - though that could just be the file scan.
0
 
kretzschmarCommented:
let me know, if i should reopen this question

if u use a memory maped file, then there may more possibilities,
but then i need more information and time to try

meikl ;-)
0
 
kretzschmarCommented:
ok, keep me informed

(just again: see your last comment not, before posting)

meikl ;-)
0
 
hibbidijiAuthor Commented:
Alright,
When using your OR operator for that open action, I do not get the error that the file is in use at all.   My biggest problem seems to be in this function now.  It is supposed to open the file and count the number of characters in it. The files I'm dealing with are fairly small - under 10mb in general - and when run on an unlocked file it takes less than 2 seconds.  

When running this function on my locked file, it returns -1 instead of the correct number of characters.

Any idea why? I believe it's related to the question's original issue

note that in the following function I've also tried the flag FILE_FLAG_RANDOM_ACCESS in the createfile.


function GetFileLengthInCharacters(filename:string):integer;
var
filesize:integer;
FileHandle:tHandle;
CharCounter:integer;
begin


 FileHandle := CreateFile(pansichar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
 CharCounter := GetFileSize(FileHandle, nil);
 fileclose(filehandle);
 result := charcounter;

end;
0
 
kretzschmarCommented:
?? would not be the charcount the filsize -1
(the filesize could be retrieved with the findfirst-api without open the file)

explain a bit more

meikl ;-)
0
 
hibbidijiAuthor Commented:
Perhaps I'm amiss here in that I misunderstood something that another programmer did because of his var names.   As I look now it does look like this is a roundabout way of doing it.   How would you rewrite the function to return the filesize?  What do you think the best way would be.

Remember that the output of this function should return a value that would be appropriate to the input of the tail function in my first post.  

thank you.
0
 
kretzschmarCommented:
maybe this way (not tested, just from head)

function getsize(APathFileName : String) : Integer;
var SRec : TSearchrec;
begin
  result := 0;
  try
    if findfirst(APathFileName, faAnyFile, SRec) > 0 then
      result := srec.Size;
  finally
    findclose(srec);
  end;
end;

meikl ;-)
0
 
hibbidijiAuthor Commented:
Yikes,
No luck.  Here's the status.

if I copy off a backup of the file, get the length, then use that for the input in the tail function, it DOES return data properly. This implies that the filestream that tail uses is good and it IS reading the file properly using that method.

The first method I used returns properly on the backup (unlocked) file and -1 on the locked file.

The findfirst method you pasted returns 0.  I modified it to return the actual return value (checking for a -1 or other errorcode but it's actually returning 0.  This would imply that it's not finding the file, I would assume.  However, i've been using the same var and value for the file as in the tail function so I can assume that it is indeed valid.   A caveat here is that the file I'm working with is on a UNC path i.e. \\domain\server\folder\file.txt

I did not find anything that states that UNC paths are not valid when using findfirst.

Any more ideas?  I CAN go back to copying to a temp file but it's obviously not the ideal solution.

0
 
kretzschmarCommented:
too late for me today to look deeper into your problem,
do you have a chance to change the "writer-process"?

until tomorrow (from my point)

meikl ;-)
0
 
hibbidijiAuthor Commented:
Back.
Sorry for the delay!
I never did get it to read from the file.  This is odd for a couple reasons:

windows can copy it without unlocking it
text editors can read from it without unlocking it

findfirst is still returning 0 (file not found) though the same var, which contains the path to the filename, can be used to copy the file with no issues.  the path is correct but findfirst just isn't working.

I'm about ready to give up and go with the file backup / read / etc method.  It's just frustrating because I know the file CAN be read - text editors are doing it.  I would just like to know why delphi isnt.

Ho hum
0
 
kretzschmarCommented:
well, then it should possible with delphi also

did you simple tried to read it into a richedit?
just with
richedit1.lines.loadfromfile(FileName);
?

of course just as test, not as solution

meikl ;-)
0
 
hibbidijiAuthor Commented:
No dice.
I still get the following error when trying the loadfromfile

First chance exception at $7C812A5B. Exception class EFOpenError with message 'Cannot open file "\\server\file.txt". The process cannot access the file because it is being used by another process'. Process Project1.exe (2312)

I will repeat for clarity that I can, every time, open the file in notepad, notepad++, word and copy it through explorer

This is perplexing isn't it?
0
 
hibbidijiAuthor Commented:
to save possible time and confusion it should be noted that I replaced my actual filename and path with the \\server\file.txt
0
 
hibbidijiAuthor Commented:
Last (for today at least)
I wrote up a function in C++ that I would use to read the filesize but it ALSO returns -1:

void __fastcall TForm1::Button1Click(TObject *Sender)
{

   FILE *fp;
   int letter;

   if((fp = fopen("\\server\file.txt", "r")) == NULL)
   {
DWORD dwSizeLo, dwSizeHi;
dwSizeLo = GetFileSize ( fp, &dwSizeHi);
char buffer[35];
String mysize = ltoa(dwSizeLo, buffer, 10);
lbl->Caption = mysize;
   }

   fclose(fp);

}



No luck with this either.  This is really perplexing!
0
 
kretzschmarCommented:
>This is really perplexing!
thats true

i will try to setup a similar case

meikl ;-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.