Files
dyp/pas/uSafeLog.pas
2026-05-07 20:25:34 +08:00

830 lines
24 KiB
ObjectPascal
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
unit uSafeLog;
interface
uses Windows,SysUtils,ComObj,Messages,System.DateUtils,System.Classes,System.IOUtils,
System.StrUtils, FMX.Grid, FMX.Dialogs, FMX.Forms, uExceptionHandler, uLogManager, uConfigManager;
const
WRITE_LOG_DIR = 'log\'; // 记录日志默认目录
LOG_TIME_FORMAT = 'yyyy/mm/dd hh:nn:ss.zzz'; // 日志显示添加时间的格式
SHOW_LOG_CLEAR_COUNT = 1000; // 日志显示容器最大显示条数
type
TLogLevel=(lgvHint, lgvError, lgvWarning, lgvMessage, lgvDebug);
TLogLevels = set of TLogLevel;
const
TLogLevelCaption: array [TLogLevel] of string = ('[Hint]:','[Error]:','[Warning]:','[Info]:','[Debug]:');
type
TSafeLog = class
private
FFileStream: TFileStream; // 文件流
FLogShower: TComponent; // 日志显示容器
FLogDay: TDateTime; // 日志当天天数
FEnabled: Boolean;
FPrefixFile:string; //日志文件前缀
FLogFileDir: string; // 日志目录
FUtf8Ready: Boolean;
procedure SetEnabled(const Value: Boolean);
procedure SetLogFileDir(const Value: string);
function EnsureUtf8FileReady(const AFileName: string): Boolean;
protected
public
FileName:string;
procedure WriteLog(Log: String; const LogLevel: TLogLevel = lgvHint); overload;
procedure WriteLog(Log: String; const Args: array of const;const LogLevel: TLogLevel = lgvHint); overload;
procedure WriteLog(AException: Exception;const LogLevel: TLogLevel = lgvError); overload;
procedure Error(const AMessage: string);overload;
procedure Error(const AMessage: string;const Args: array of const);overload;
procedure Hint(const AMessage: string);overload;
procedure Hint(const AMessage: string;const Args: array of const);overload;
procedure Warn(const AMessage: string);overload;
procedure Warn(const AMessage: string;const Args: array of const);overload;
procedure Debug(const AMessage: string);overload;
procedure Debug(const AMessage: string;const Args: array of const);overload;
procedure MessageInfo(const AMessage: string);overload;
procedure MessageInfo(const AMessage: string;const Args: array of const);overload;
procedure MessageError(const AMessage: string;const Args: array of const);overload;
constructor Create(PrefixFile:string);
destructor Destroy; override;
// 是否允许记录日志
property Enabled: Boolean read FEnabled write SetEnabled;
// 日志文件目录,默认当前目录的Log目录
property LogFileDir: string read FLogFileDir write SetLogFileDir;
end;
TDataSavaLog = class
private
FFileStream: TFileStream; // 文件流
FLogShower: TComponent; // 日志显示容器
FLogDay: TDateTime; // 日志当天天数
FEnabled: Boolean;
fFileName:string; //文件名
FPrefixFile:string; //日志文件前缀
FLogFileDir: string; // 日志目录
FUtf8Ready: Boolean;
procedure SetEnabled(const Value: Boolean);
procedure SetLogFileDir(const Value: string);
function EnsureUtf8FileReady(const AFileName: string): Boolean;
protected
public
FileName:string;
procedure WriteLog(Log: String; const LogLevel: TLogLevel = lgvHint); overload;
procedure DelFile(const sFname:string); overload;
function OpenLog(sFileLog: String;var f: TStrings):Boolean; overload;
procedure MessageInfo(const sFname:string;const AMessage: string);overload;
constructor Create(PrefixFile:string;Const WRITE_LOG_SaveDIR:string='DataSava\');
destructor Destroy; override;
// 是否允许记录日志
property Enabled: Boolean read FEnabled write SetEnabled;
// 日志文件目录,默认当前目录的Log目录
property LogFileDir: string read FLogFileDir write SetLogFileDir;
end;
function WorkLog():TSafeLog;
function DbApiLog():TSafeLog;
function RfidLog():TSafeLog;
function DataLog():TSafeLog;
function DataSavaLog(sFName: string):TDataSavaLog;
procedure LogDebug(msg:string);inline;overload; //用于代码测试输出
procedure LogDebug(Log: String; const Args: array of const);overload;
procedure CopyLogFile(DestPath:string);
procedure ExportToExcel(FName: String;RzStrGrid: TStringGrid);//导出到Excel
var
FWorkLog:TSafeLog;
FDbApiLog,FRfidLog,FDataLog:TSafeLog;
FDataSavaLog:TDataSavaLog;
implementation
uses uShowInfo;
function IsValidUtf8(const bytes: TBytes): Boolean;
var
i, extra: Integer;
b: Byte;
begin
Result := True;
i := 0;
while i < Length(bytes) do
begin
b := bytes[i];
if (b and $80) = 0 then
begin
Inc(i);
Continue;
end
else if (b and $E0) = $C0 then
extra := 1
else if (b and $F0) = $E0 then
extra := 2
else if (b and $F8) = $F0 then
extra := 3
else
Exit(False);
if i + extra >= Length(bytes) then
Exit(False);
Inc(i);
while (extra > 0) do
begin
if (bytes[i] and $C0) <> $80 then
Exit(False);
Inc(i);
Dec(extra);
end;
end;
end;
function TSafeLog.EnsureUtf8FileReady(const AFileName: string): Boolean;
var
hdr: array[0..2] of Byte;
fsCheck: TFileStream;
needConvert: Boolean;
legacyText: string;
data: TBytes;
begin
Result := True;
if (AFileName = '') then Exit;
try
if FileExists(AFileName) then
begin
needConvert := False;
fsCheck := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
try
if fsCheck.Size > 0 then
begin
FillChar(hdr, SizeOf(hdr), 0);
fsCheck.Read(hdr, SizeOf(hdr));
if (hdr[0]=$EF) and (hdr[1]=$BB) and (hdr[2]=$BF) then
needConvert := False
else
begin
// 无BOM:读取全部检测是否为有效UTF-8
fsCheck.Position := 0;
SetLength(data, fsCheck.Size);
if fsCheck.Size > 0 then
fsCheck.ReadBuffer(data[0], fsCheck.Size);
needConvert := not IsValidUtf8(data);
end;
end;
finally
fsCheck.Free;
end;
if needConvert then
begin
legacyText := TFile.ReadAllText(AFileName, TEncoding.ANSI);
TFile.WriteAllText(AFileName, legacyText, TEncoding.UTF8);
end;
end;
except
on E: Exception do
Result := False;
end;
end;
function TDataSavaLog.EnsureUtf8FileReady(const AFileName: string): Boolean;
var
hdr: array[0..2] of Byte;
fsCheck: TFileStream;
needConvert: Boolean;
legacyText: string;
data: TBytes;
begin
Result := True;
if (AFileName = '') then Exit;
try
if FileExists(AFileName) then
begin
needConvert := False;
fsCheck := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
try
if fsCheck.Size > 0 then
begin
FillChar(hdr, SizeOf(hdr), 0);
fsCheck.Read(hdr, SizeOf(hdr));
if (hdr[0]=$EF) and (hdr[1]=$BB) and (hdr[2]=$BF) then
needConvert := False
else
begin
fsCheck.Position := 0;
SetLength(data, fsCheck.Size);
if fsCheck.Size > 0 then
fsCheck.ReadBuffer(data[0], fsCheck.Size);
needConvert := not IsValidUtf8(data);
end;
end;
finally
fsCheck.Free;
end;
if needConvert then
begin
legacyText := TFile.ReadAllText(AFileName, TEncoding.ANSI);
TFile.WriteAllText(AFileName, legacyText, TEncoding.UTF8);
end;
end;
except
on E: Exception do
Result := False;
end;
end;
function WorkLog():TSafeLog;
begin
if FWorkLog = nil then
begin
FWorkLog := TSafeLog.Create('work');
FWorkLog.Enabled:=true;
end;
Result := FWorkLog;
end;
function DbApiLog():TSafeLog;
begin
if FDbApiLog = nil then
begin
FDbApiLog := TSafeLog.Create('Api');
FDbApiLog.Enabled:=true;
end;
Result := FDbApiLog;
end;
function RfidLog():TSafeLog;
begin
if FRfidLog = nil then
begin
FRfidLog := TSafeLog.Create('Rfid');
FRfidLog.Enabled:=true;
end;
Result := FRfidLog;
end;
function DataLog():TSafeLog;
begin
if FDataLog = nil then
begin
FDataLog := TSafeLog.Create('Data');
FDataLog.Enabled:=true;
end;
Result := FDataLog;
end;
function DataSavaLog(sFName: string):TDataSavaLog;
begin
if FDataSavaLog = nil then
begin
FDataSavaLog := TDataSavaLog.Create(sFName); //'D301909600'+'-'+'1688187-A01-0F'
FDataSavaLog.Enabled:=true;
end;
Result := FDataSavaLog;
end;
procedure LogDebug(msg:string);overload;
begin
outputdebugstring(pchar(msg));
end;
procedure LogDebug(Log: String; const Args: array of const);overload;
begin
outputdebugstring(pchar(Format(Log, Args)));
end;
procedure TSafeLog.Error(const AMessage: string);
begin
WriteLog(AMessage,lgvError);
LogManager.ErrorCategory(lcSystem, AMessage);
end;
procedure TSafeLog.Error(const AMessage: string;const Args: array of const);
begin
WriteLog(Format(AMessage, Args),lgvError);
LogManager.ErrorCategory(lcSystem, AMessage, Args);
end;
procedure TSafeLog.Hint(const AMessage: string);
begin
WriteLog(AMessage,lgvHint);
LogManager.TraceCategory(lcSystem, AMessage);
end;
procedure TSafeLog.Hint(const AMessage: string;const Args: array of const);
begin
WriteLog(Format(AMessage, Args),lgvHint);
LogManager.TraceCategory(lcSystem, AMessage, Args);
end;
procedure TSafeLog.Warn(const AMessage: string);
begin
WriteLog(AMessage,lgvWarning);
LogManager.WarnCategory(lcSystem, AMessage);
end;
procedure TSafeLog.Warn(const AMessage: string;const Args: array of const);
begin
WriteLog(Format(AMessage, Args),lgvWarning);
LogManager.WarnCategory(lcSystem, AMessage, Args);
end;
procedure TSafeLog.Debug(const AMessage: string);
begin
WriteLog(AMessage,lgvDebug);
LogManager.DebugCategory(lcSystem, AMessage);
end;
procedure TSafeLog.Debug(const AMessage: string;const Args: array of const);
begin
WriteLog(Format(AMessage, Args),lgvDebug);
LogManager.DebugCategory(lcSystem, AMessage, Args);
end;
procedure TSafeLog.MessageInfo(const AMessage: string);
begin
WriteLog(AMessage,lgvMessage);
LogManager.InfoCategory(lcSystem, AMessage);
end;
procedure TSafeLog.MessageInfo(const AMessage: string;const Args: array of const);
begin
WriteLog(Format(AMessage, Args),lgvMessage);
LogManager.InfoCategory(lcSystem, AMessage, Args);
end;
procedure TSafeLog.MessageError(const AMessage: string;const Args: array of const);
begin
WriteLog(Format(AMessage, Args),lgvMessage);
LogManager.ErrorCategory(lcSystem, AMessage, Args);
end;
procedure TSafeLog.WriteLog(Log: String; const Args: array of const;const LogLevel: TLogLevel = lgvHint);
begin
WriteLog(Format(Log, Args), LogLevel);
end;
procedure TSafeLog.WriteLog(AException: Exception;const LogLevel: TLogLevel = lgvError);
begin
WriteLog(AException.Message,lgvError);
end;
procedure TSafeLog.SetEnabled(const Value: Boolean);
begin
FEnabled := Value;
end;
procedure TSafeLog.SetLogFileDir(const Value: string);
begin
FLogFileDir := Value;
if not DirectoryExists(FLogFileDir) then
if not ForceDirectories(FLogFileDir) then //创建目录
begin
RaiseDataException('日志路径错误,日志类对象不能被创建', 2001);
end;
end;
constructor TSafeLog.Create(PrefixFile:string);
begin
FLogShower := nil;
FLogDay:=-1;
FPrefixFile:=PrefixFile;
LogFileDir := ExtractFilePath(ParamStr(0)) + WRITE_LOG_DIR;
end;
destructor TSafeLog.Destroy;
begin
if Assigned(FFileStream) then
FreeAndNil(FFileStream);
end;
procedure TSafeLog.WriteLog(Log: String; const LogLevel: TLogLevel = lgvHint);
var
logName: String;
fMode: Word;
bytes: TBytes;
begin
System.TMonitor.Enter(self);
try
if FLogDay<>Date then
begin
logName := FPrefixFile+FormatDateTime('yyyymmdd', Now) + '.log'; //
FLogDay:=Date;
FileName:=FLogFileDir + logName;
if FileExists(FileName) then // 如果当天的日志文件存在
fMode := fmOpenWrite or fmShareDenyNone
else
fMode := fmCreate or fmShareDenyNone;
if Assigned(FFileStream) then
FreeAndNil(FFileStream);
FFileStream := TFileStream.Create(FLogFileDir + logName, fMode);
end;
FFileStream.Seek(0,soEnd); // 追加到最后
if Log='' then
Log:=#13#10
else
begin
Log:=TLogLevelCaption[LogLevel]+#9+Log;
Log := FormatDateTime(LOG_TIME_FORMAT, Now) + #9 + Log + #13#10;
end;
// 修复乱码问题:添加UTF-8 BOM并使用正确的编码
if (FFileStream.Size = 0) then
begin
// 添加UTF-8 BOM以避免乱码
bytes := [$EF, $BB, $BF]; // UTF-8 BOM
FFileStream.Write(bytes, Length(bytes));
end;
bytes := TEncoding.UTF8.GetBytes(Log);
FFileStream.Write(bytes, Length(bytes));
finally
System.TMonitor.Exit(self);
end;
end;
function CombinePath(QPathA: string; QPathB: string): string;
var
lSeparatorChar: string;
lReplaceChar: string;
begin
lSeparatorChar := TPath.DirectorySeparatorChar;
lReplaceChar := '/';
if lSeparatorChar = '/' then
begin
lReplaceChar := '\';
end;
QPathA := QPathA.Replace(lReplaceChar, lSeparatorChar);
QPathB := QPathB.Replace(lReplaceChar, lSeparatorChar);
if RightStr(QPathA,1)<>lSeparatorChar then
QPathA:=QPathA+lSeparatorChar;
if QPathB.Length > 0 then
begin
if QPathA.Length > 0 then
begin
// 判断第一个是不是 lSeparatorChar,是的话去除
if leftStr(QPathB, 1) = lSeparatorChar then
begin
QPathB := QPathB.Substring(1, QPathB.Length - 1);
end;
end;
end;
result := TPath.Combine(QPathA, QPathB);
end;
procedure CopyLogFile(DestPath:string);
begin
TThread.CreateAnonymousThread( // 创建一个匿名线程,
procedure
var
FileName:string;
begin
try
FileName:=CombinePath(DestPath,TPath.GetDirectoryName(FWorkLog.FileName));
Copyfile(Pchar(FWorkLog.FileName),Pchar(FileName),false);
FileName:=CombinePath(DestPath,TPath.GetDirectoryName(FDbApiLog.FileName));
Copyfile(Pchar(FDbApiLog.FileName),Pchar(FileName),false);
FileName:=CombinePath(DestPath,TPath.GetDirectoryName(FRfidLog.FileName));
Copyfile(Pchar(FRfidLog.FileName),Pchar(FileName),false);
except
on e:Exception do
begin
workLog.Error('上传日志出错:%s',[e.Message]);
end;
end;
end).Start;
end;
procedure Stringgridtoexcel(atitle: string;Astringgrid: TStringGrid; Afontsize: integer);
var
xlapp, xlsheet: variant;
row, CCC, nnn, jjj: integer;
begin
try
xlapp := createoleobject('excel.application');
except
// showmessage('not found excel in your system, so can not create file!');
exit;
end;
try
ccc := AstringGrid.ColumnCount;
xlapp.workbooks.add; //添加新工作簿
xlapp.visible := false;
xlsheet := xlapp.activesheet;
xlapp.activewindow.windowstate := 2;
xlapp.range[xlsheet.cells[1, 1], xlsheet.cells[1, ccc]];//.MERGE;
xlsheet.cells[1, 1] := Atitle; //页头第一行;
// xlsheet.cells[1, 1].HorizontalAlignment := -4108;
row := 2;
for jjj := 0 to Astringgrid.RowCount - 1 do
begin
for nnn := 1 to ccc do
xlsheet.cells[row, nnn] := trim(Astringgrid.Cells[nnn - 1, row - 2]);
// xlsheet.rows[row].RowHeight := 18;
inc(row);
end;
xlapp.visible := true;
//格式调整
// xlapp.range[xlsheet.cells[row, 1], xlsheet.cells[row, 13]].WrapText := True;
// xlapp.range[xlsheet.cells[row, 1], xlsheet.cells[row, 13]].HorizontalAlignment := -4108;
xlsheet.pagesetup.headerMargin := 1 / 0.035; //页眉到顶端边距1cm
xlsheet.pagesetup.footerMargin := 0.6 / 0.035; //页脚到底端边距1cm
xlsheet.pagesetup.topMargin := 1 / 0.035; //顶边距1cm
XLSHEET.pagesetup.bottomMargin := 1.3 / 0.035; //底边距1cm
xlsheet.pagesetup.leftMargin := 0.5 / 0.035; //左边距1cm
xlsheet.pagesetup.rightMargin := 0.5 / 0.035; //右边距1cm
// xlsheet.pagesetup.leftfooter := '制表: ' + Puboptername;
xlsheet.pagesetup.centerfooter := ''; //页脚
xlsheet.pagesetup.rightfooter := '第&P页/共&N页';
xlsheet.pagesetup.leftHeader := '';
xlsheet.pagesetup.orientation := 1; //横向
xlsheet.pagesetup.printtitlerows := '$1:$1';
// xlsheet.rows[1].font.name := '宋体'; //设置第一行字体属性
// xlsheet.rows[1].font.bold := true;
// xlsheet.rows[1].font.size := 20;
// xlsheet.rows[1].RowHeight := 28;
// for nnn := 1 to ccc do
// begin
// xlsheet.columns[nnn].columnwidth := Astringgrid.ColWidths[nnn - 1] * 0.1188;
// end;
// for nnn := 1 to 4 do begin
// xlapp.range[xlsheet.cells[2, 1], xlsheet.cells[row - 1, CCC]].borders[nnn].linestyle := 1;
// xlapp.range[xlsheet.cells[2, 1], xlsheet.cells[row - 1, CCC]].borders[nnn].weight := 1;
// end;
// xlapp.range[xlsheet.cells[2, 1], xlsheet.cells[row - 1, CCC]].font.size := Afontsize;
// xlapp.range[xlsheet.cells[2, 1], xlsheet.cells[row - 1, ccc]].WrapText := True;
varclear(xlsheet);
varclear(xlapp);
except
on E: Exception do
begin
xlapp.quit;
// showMSG('出现错误' + E.message, '错误', 1);
end;
end;
end;
//把他写成了一个过程,这样其他用到这个StringGrid的控件都可以刁永红这个来导出了
procedure ExportToExcel(FName: String;RzStrGrid: TStringGrid);
const
xlNormal = -4143;
var
i, j, k, l: integer;
filename: string;
excel, Vrange: OleVariant;
savedialog: TSaveDialog;
begin
filename := ExtractFilePath(Paramstr(0))+'log\'+FName;
if RzStrGrid.RowCount > 65536 then
begin
// if application.messagebox('需要导出的数据过大,Excel最大只能容纳65536行,是否还要继续?', '询问', mb_yesno + mb_iconquestion) = idno then
exit;
end;
// screen.Cursor := crHourGlass;
try
excel := CreateOleObject('Excel.Application');
excel.workbooks.add;
except
// screen.cursor := crDefault;
showmessage('无法调用Excel');
exit;
end;
// savedialog := TSaveDialog.Create(nil);
// savedialog.Filter := 'Excel文件(*.xls)|*.xls';
// if savedialog.Execute then
// begin
// if FileExists(savedialog.FileName) then
// try
// if ShowInfoOKCancel('该文件已经存在,要覆盖吗?') then
// DeleteFile(PChar(savedialog.FileName))
// else
// begin
// excel.Quit;
// savedialog.free;
// // screen.cursor := crDefault;
// Exit;
// end;
// except
// excel.Quit;
// savedialog.free;
// // screen.cursor := crDefault;
// Exit;
// end;
// filename := savedialog.FileName;
// end;
// savedialog.free;
if filename = '' then
begin
excel.Quit;
// screen.cursor := crDefault;
exit;
end;
//设置字体
excel.Cells.Font.Size := 10;
//导出数据到Excel
for i := 0 to RzStrGrid.RowCount - 1 do
begin
for j := 0 to RzStrGrid.ColumnCount - 1 do
begin
excel.Cells[i + 1, j + 1] := RzStrGrid.Cells[j, i];
end;
end;
//设置列宽
// excel.ActiveSheet.Columns[3].ColumnWidth := 15;
//需要合并的单元格
Vrange := excel.range[excel.cells[RzStrGrid.RowCount + 1, 1], excel.cells[RzStrGrid.RowCount + 1, RzStrGrid.ColumnCount]];
Vrange.Select;
//合并单元格
Vrange.Merge(True);
//合并后单元格内容的字体大小
Vrange.Font.Size := 15;
Vrange.Font.Bold := True;
//合并单元格后的背景色
Vrange.Interior.ColorIndex := 6;
////最后一行加一个注解
//excel.cells[RzStrGrid.RowCount + 1, 1] := '注意:导出Excel和上一篇文章导出的Excel模板一样,可以进行导入导出';
//整页的文本全都居中
excel.columns.HorizontalAlignment := 3;
try
//判断文件名后缀是不是.xls
if copy(filename, length(filename) - 3, 4) <> '.xls' then
filename := filename + '.xls';
//保存Excel
excel.ActiveWorkbook.SaveAs(filename, xlNormal, '', '', False, False);
except
excel.Quit;
// screen.cursor := crDefault;
exit;
end;
// excel.Visible := true; //打开文件
// screen.cursor := crDefault;
end;
{ TDataSavaLog }
constructor TDataSavaLog.Create(PrefixFile: string;Const WRITE_LOG_SaveDIR:string='DataSava\');
begin
FLogShower := nil;
FLogDay:=-1;
FPrefixFile:=PrefixFile;
LogFileDir := ExtractFilePath(ParamStr(0)) + WRITE_LOG_SaveDIR;
end;
destructor TDataSavaLog.Destroy;
begin
if Assigned(FFileStream) then
FreeAndNil(FFileStream);
end;
procedure TDataSavaLog.WriteLog(Log: String; const LogLevel: TLogLevel = lgvHint);
var
logName: String;
fMode: Word;
bytes: TBytes;
hdr: array[0..2] of Byte;
fsCheck: TFileStream;
needConvert: Boolean;
legacyText: string;
begin
System.TMonitor.Enter(self);
try
if fFileName<>FPrefixFile then
begin
FPrefixFile:= fFileName;
logName := FPrefixFile + '.log'; //+FormatDateTime('yyyymmdd', Now)
FLogDay:=Date;
FileName:=FLogFileDir + logName;
FUtf8Ready := EnsureUtf8FileReady(FileName);
if FileExists(FileName) then // 如果当天的日志文件存在
begin
// 若历史文件不是UTF-8 BOM,转为UTF-8 BOM
needConvert := False;
fsCheck := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
try
if fsCheck.Size > 0 then
begin
FillChar(hdr, SizeOf(hdr), 0);
fsCheck.Read(hdr, SizeOf(hdr));
needConvert := not ((hdr[0]=$EF) and (hdr[1]=$BB) and (hdr[2]=$BF));
end;
finally
fsCheck.Free;
end;
if needConvert then
begin
legacyText := TFile.ReadAllText(FileName, TEncoding.ANSI);
TFile.WriteAllText(FileName, legacyText, TEncoding.UTF8);
end;
fMode := fmOpenWrite or fmShareDenyNone
end
else
fMode := fmCreate or fmShareDenyNone;
if Assigned(FFileStream) then
FreeAndNil(FFileStream);
FFileStream := TFileStream.Create(FLogFileDir + logName, fMode);
end;
// 非跨文件写入时,也确保为UTF-8
if (not FUtf8Ready) and (FileName <> '') then
begin
FUtf8Ready := EnsureUtf8FileReady(FileName);
end;
FFileStream.Seek(0,soEnd); // 追加到最后
if Log='' then
Log:=#13#10
else
begin
Log:=Log+#13#10;
// Log:=TLogLevelCaption[LogLevel]+#9+Log;
// Log := FormatDateTime(LOG_TIME_FORMAT, Now) + #9 + Log + #13#10;
end;
// 使用UTF-8编码,并在新文件写入BOM
if (FFileStream.Size = 0) then
begin
bytes := [$EF, $BB, $BF];
FFileStream.Write(bytes, Length(bytes));
end;
bytes := TEncoding.UTF8.GetBytes(Log);
FFileStream.Write(bytes, Length(bytes));
finally
System.TMonitor.Exit(self);
end;
end;
procedure TDataSavaLog.MessageInfo(const sFname: string; const AMessage: string);
begin
try
fFileName := sFname;
WriteLog(AMessage, lgvMessage);
except
on E: Exception do
begin
// 静默处理日志记录异常
end;
end;
end;
// 添加繁简转换函数
function TraditionalToSimplified(const str: string): string;
begin
// 在实际应用中,这里应该实现繁体到简体的转换逻辑
// 目前只是返回原字符串,需要根据实际需求实现转换算法或使用转换库
Result := str;
end;
function TDataSavaLog.OpenLog(sFileLog: String; var f: TStrings): Boolean;
var
sloadLog: String;
begin
Result := False;
try
// ExtractFilePath(ParamStr(0)) +
sloadLog := (ExtractFilePath(ParamStr(0)) + 'DataSava\' + sFileLog);
DbApiLog.MessageInfo('文件sloadLog:' + sloadLog);
// True,若拷贝过去的文件路径下已存在相同文件,那么不替换文件。// False,若拷贝过去的文件路径下已存在相同文件,那么会替换掉文件。//-----------------------------
CopyFile(PWideChar(Config.GetFileServerPath + '\' + sFileLog), PWideChar(sLoadLog), True);
f.LoadFromFile(sLoadLog);
Result := True;
except
on E: Exception do
begin
// 静默处理文件打开异常
end;
end;
end;
procedure TDataSavaLog.DelFile(const sFname:string);
begin
try
// DeleteFile('\\192.168.0.250\DataSava\'+sFname);
WINEXEC(PAnsiCHAR('CMD /C DEL /Q/F ' + Config.GetFileServerPath + '\' + sFname), SW_HIDE); Sleep(1000);
except
end;
end;
procedure TDataSavaLog.SetEnabled(const Value: Boolean);
begin
FEnabled := Value;
end;
procedure TDataSavaLog.SetLogFileDir(const Value: string);
begin
FLogFileDir := Value;
if not DirectoryExists(FLogFileDir) then
if not ForceDirectories(FLogFileDir) then //创建目录
begin
RaiseDataException('日志路径错误,日志类对象不能被创建', 2001);
end;
end;
end.