Link to home
Start Free TrialLog in
Avatar of hibbidiji
hibbidiji

asked on

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!
ASKER CERTIFIED SOLUTION
Avatar of kretzschmar
kretzschmar
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of hibbidiji
hibbidiji

ASKER

Hiya Michael!
How about workarounds?   Executing a file copy then reading that temp file?   Anything else you can think of?
Thanks!
>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 ;-)
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;

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


can you copy the file?

meikl ;-)
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?
Sorry for the cross post-  looks like this is the solution.   Thanks for pointing me at the untouchable file and have a great day.
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 ;-)
trying your solution now - will request a change if we get it fixed with your method
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 ;-)
puh, seems i am too slow :-))
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.
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 ;-)
ok, keep me informed

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

meikl ;-)
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;
?? 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 ;-)
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.
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 ;-)
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.

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 ;-)
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
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 ;-)
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?
to save possible time and confusion it should be noted that I replaced my actual filename and path with the \\server\file.txt
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!
>This is really perplexing!
thats true

i will try to setup a similar case

meikl ;-)