Delphi - Sharing violation opening text file
Asked Answered
O

5

6

I'm trying to open a text file for reading in a Delphi 7 app, but am getting I/O error 32 (sharing violation) because another application already has the file open. I've tried setting FileMode to "fmOpenRead or fmShareDenyNone" but now realise this doesn't apply to text files anyway.

Is there a way of reading text files that are open by another application?

var
  f: TextFile;
begin
  FileMode := fmOpenRead or fmShareDenyNone;   // FileMode IS NOT APPLICABLE TO TEXT FILES!!
  AssignFile(f, FileName);
  Reset(f);
Ormand answered 26/4, 2009 at 11:9 Comment(5)
Why are you so keen on text files? Why not use the stream classes which allow for proper file access and sharing modes?Kurr
because I want to read a single line at a time, and TFileStream doesn't have methods for that. I suppose I could read a buffer full and split on CR/LF.Ormand
You can use TStreamReader to read lines from a TFileStream. It has a ReadLine() method, and does the buffering internally for you.Kali
@RemyLebeau - I tried using TStreamReader and it seems to give the access violation when the file is open by another application.Antecedency
@Antecedency that is not an access violation (accessing an invalid memory address), that is a sharing violation (opening the file for rights that are not allowed by another open handle to the same file). Those are two different things. You can still use TStreamReader, just open the file with a TFileStream first with sufficient sharing rights (fmOpenRead or fmShareDenyNone is usually fine, unless the other handle has exclusive access to the file), and then pass the TFileStream to TStreamReader for reading.Kali
M
13

Use the LoadFromStream method of TStringList, rather than LoadFromFile. You get to control the locking that way:

var
    slFile: TStrings;
    stream: TStream;
begin
   slFile := TStringList.Create;
   try
      stream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone);
      try 
         slFile.LoadFromStream(stream);
      finally
         stream.Free;
      end;

      //Use the stringlist
   finally
      slFile.Free;
   end;
end;

That example is using the stream to load into a TStringList. If you only want to read pieces, you can do that. Just read from the stream.

Mastersinger answered 12/5, 2010 at 2:45 Comment(1)
This works and solve the issue. Only concern is about memory usage: whole file is loaded into memory. This could be an issue.Willock
A
3

It depends on how that other process opened the file... If it opened the file exclusively you are not going to succeed at all.

And TextFile is old hat, I think it will open in exclusive mode to be compatible with Old style DOS. You should use TFileStream or similar.

TStringList may also work, again depending on what the other process is doing. But if the file is being written (like a .log file) the fmShareDenyWrite won't work.

Anchoveta answered 26/4, 2009 at 12:40 Comment(4)
I don't know how the other process is opening the file, but Notepad can open it successfully while it is being written to.Ormand
Than it looks like you're in luck. Just ditch TextFile.Anchoveta
@Simes, I outline a process that shows you exactly how the files are being opened, here: https://mcmap.net/q/1631578/-log-file-monitor/…Dandridge
@Ormand use Process Monitor to find out how a file is opened and with what sharing rights.Kali
P
2

Maybe like this:

  vFileList := TStringList.Create;
  try
    vFileStream := TFileStream.Create('myfile.txt', fmOpenRead or fmShareDenyNone);
    try
      vFileList.LoadFromStream(vFileStream);
    finally
      vFileStream.Free;
    end;
    // Use vFileList
  finally
    vFileList.Free;
  end;
Perjure answered 28/4, 2009 at 8:54 Comment(0)
B
1

This will solve your problem instantly. Load the file using a TStringList. Just call:

...
var sl: TStringList;
begin
  sl := TStringList.create();
  try
    sl.loadFromFile(Filename);
    ...do your stuff here...
  finally
    freeAndNil(sl);
  end;
end;

I found that dealing with text files, it's best to use the TStringList. Otherwise I'd go for TFileStream and there you can specify your opening mode.

Boling answered 26/4, 2009 at 11:24 Comment(6)
LoadFromFile() uses (at least in Delphi 5 and 2007 it does) "fmOpenRead or fmShareDenyWrite" for the mode. This is definitely not what the OP is wanting.Kurr
??? This is exactly what Simes wants, though. He just wants to READ the file without caring about other processes using it. That was exactly his question.Penland
@MasterPeter, I believe the cullprit mghie is talking about is fmShareDenyWrite.fmShareDenyWrite "locks" a file so other processes can only read... A bit harsh though to downvote your answer because of it.Engstrom
The problem with this is that it loads the whole file into memory. Some of the files can be big, and so I prefer to process them one line at a time.Ormand
@Lieven: You're right on both accounts (I didn't downvote the answer either). @MasterPeter: Opening the file will fail if another process has it open for writing (non-exclusive). fmShareDenyNone is necessary in that case.Kurr
I just tried this and you're both right, it doesn't work if the other process has a fmOpenWrite access to it. However, I doubt Simes has this problem. (S)he just wants to read the file line by line and TextFile(s) doesn't seem to work for him/her. I haven't used TextFiles in all my life (I always used TStringLists whenever I needed to treat something as a text file), so I can't help any more than I already have attempted to :)Penland
F
1

If I remember correctly, there is also a Textfilemode Variable that applies to text files only.

Footwear answered 26/4, 2009 at 12:44 Comment(1)
That would be perfect, but it doesn't compile and can't find it in the help.Ormand

© 2022 - 2024 — McMap. All rights reserved.