いつもお世話になっております。
下記のような感じで、テキストにログを書いていますが、
二重起動させると、同じテキストを開く仕様の為、
「I/O エラー (32)」が出てしまいます。
出来れば「Writeln」を使い、同じテキストに書き込みたい
のですが、なにか良い解決方法はないでしょうか?
よろしくお願いします。
var
LogFH : TextFile; //ログ用
begin
AssignFile(LogFH, strLogFile);
if FileExists(strLogFile) then
Append(LogFH) //ログ追加
else
Rewrite(LogFH); //ログ新規
Writeln(LogFH, 'ログ内容');
CloseFile(LogFH);
end;
同じファイルに同時にアクセスはできません。
IOエラーが出たら少し時間を置いて書き込みを再挑戦するくらいしかないと思います。
アプリを二重起動させて同じファイルを開きたいなら、FileOpen のような Pascalネイティブでないファイル変数ハンドラを使いましょ。
FileHandle := FileOpen(strLogFile, fmOpenReadWrite or fmShareDenyNone);
※PascalネイティブなTFileStreamを使っても可。
ファイル末にログを追加するだけなら、リダイレクトの">>"が使えるかも。
それでだめなら、
ほかからの書き込みを禁止するモードでファイルを開く。
ファイルのオープンに失敗した場合は、他のアプリが書き込み中と判断して書き込みをしない。
代わりにSleep()で一定時間待機してから再度書き込みを行う。
できれば、ミューテックスを使って同期処理を入れたほうがいいけど初心者には難しい。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpdndllpro/htm/metrsect.asp
.iniファイルなら同時にアクセスできますが、
これはこれで、色々と(データ設計など)工夫が要りそうですね・・・
メラトニンさん、あえてさん、moroさん、deldelさん、ありがとうございます。
AssignFile・Append・Writelnでは、やはり不可能なんですね。
仕方ないので、ログのデータを保持して、プログラム最後に一気に書き込むようにしようかと思います。
1)「CreateFile・SetFilePointer・WriteFile・CloseHandle」を使い、「CreateFile・SetFilePointer」の時点で処理1を止め、処理2が同じ行動をとると、ログファイルの内容が破壊されてしまいます。ファイルポインタは終点を指定していますが、その辺あたりのことでしょうか・・・
2)以下のコードだと、うまく書き出せません(空のファイルが出来上がってしまう)。
function WriteData(strFileName: string):Boolean;
var
FileHandle : Integer;
chrBuf: array[0..2048] of char; //文字列データ(関数呼び出し用途)
begin
//ファイル存在確認
if not FileExists(strIniFile) then
FileCreate(strFileName)
else
FileHandle := FileOpen(strFileName, fmOpenWrite);
//書き込み
if FileHandle > 0 then begin
StrCopy(chrBuf, PChar(strLogBuf));
FileWrite(FileHandle, chrBuf[0], SizeOf(strLogBuf));
end;
//ファイルクローズ
FileClose(FileHandle);
end;
3)TStrings.SaveToFileを使うと、以前のログが消え、新規のファイルにログが残ってしまう。
1〜3のうち、どれかだけでも解決すればよいのですが><
ぼすけて・・・
間違えて 2)をまんま貼り付けてしまいましたが、strLogBufは外でstring型で宣言しています。
また、FileWrite(FileHandle, chrBuf[0], SizeOf(strLogBuf));は
FileWrite(FileHandle, chrBuf, SizeOf(strLogBuf));の間違いです。
すみません。
>ぼすけて・・・
ぼすけてあげてもいいけど、やめとく。
2)のコードが期待通りに動かないのは、コードに間違いがあるから。
どこが間違っているかを自力で見つけ出せれば「駆け出し」から半歩前進。
FileWriteの記述間違いかと思って、そっちばかり気を配っていました。
FileHandle:= FileCreate(strFileName);
ハンドル受け取ってなかったですね・・・ ぼす。
function WriteData(strFileName: string):Boolean;
var
FileHandle : Integer;
begin
//ファイル存在確認
if not FileExists(strIniFile) then
FileHandle:= FileCreate(strFileName)
else
FileHandle := FileOpen(strFileName, fmOpenWrite);
//書き込み
if FileHandle > 0 then begin
FileWrite(FileHandle, PChar(strLogBuf)^, length(strLogBuf));
end;
//ファイルクローズ
FileClose(FileHandle);
end;
今後のために1)と3)の不具合の原因を勉強できたらと思うんですが、なんかヒントいただけませんか?
いろいろ調べてるんですが、調べる為のキーワードがわからなくて困っております。
3)は解決不可ですかねぇ・・・
FileExists(strFileName)
今日は間違いだらけで危険なので、しっかり寝てから作り直したいと思います。
2)も結局追記になっていませんでした・・・
後は自力で解決したいと思います。
お騒がせしました・・・
>後は自力で解決したいと思います。
その心がけスバラシイ!
function WriteData(const strFileName, strLogBuf: string): Boolean;
var
FileHandle : Integer;
begin
result := False;
if not FileExists(strFileName) then
FileHandle := FileCreate(strFileName)
// FileHandle := CreateFile(PChar(strFileName), GENERIC_WRITE, FILE_SHARE_WRITE, nil,
// {OPEN_ALWAYS} CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
else
FileHandle := FileOpen(strFileName, fmOpenWrite or fmShareDenyNone);
if FileHandle > 0 then begin
// ここで停止しておけば、二重起動した別アプリがファイルに追加書き込みしても大丈夫
SetFilePointer(FileHandle, 0, nil, FILE_END); // ポインタをファイル末尾に
// ここで停止させると、二重起動した別アプリがファイルに追加した時点でポインタが末尾からずれる
FileWrite(FileHandle, PChar(strLogBuf)^, Length(strLogBuf)); // 追加書き込み
result := True;
end;
FileClose(FileHandle);
end;
果報は寝ず待てさん、ありがとうございます。
先ほどFileSeekで解決したのですが、SetFilePointerを使えば良かったんですね。
DelphiとAPIを混ぜるという発想がありませんでした・・・
> // ここで停止させると、二重起動した別アプリがファイルに追加した時点でポインタが末尾からずれる
二度末尾にセットされるとずれてしまうんですね。
1)がだめだったのも、それが原因なんですね。
なんとか書き込みのタイミングを計れるように、工夫したいと思います。
ありがとうございます!
ツイート | ![]() |