Delphi 11 Alexandria下32位VCL应用RTF转文本函数返回文件路径问题及替代方案咨询
RTF转纯文本函数问题及解决方案
一、原函数的核心问题
你的函数返回文件路径而非RTF内容,根源就在这一行代码:
MyStringStream := TStringStream.Create(RTF_FilePath);
你这里是把文件路径字符串直接作为流的内容创建了,完全没有读取指定路径下的RTF文件内容!后续RichEdit加载的只是路径文本,最后输出自然就是路径字符串了。
另外还有个细节逻辑问题:加载RTF内容时,应该先让RichEdit处于RTF模式(PlainText := False),加载完成后再切换到纯文本模式提取内容,原代码的顺序虽没直接报错,但逻辑上不够严谨。
二、修正后的TRichEdit实现(仍用无窗口控件)
如果还是想用TRichEdit的方式,只需要修正流的创建逻辑,正确读取RTF文件即可:
function RtfToText(const RTF_FilePath: string; ReplaceLineFeedWithSpace: Boolean): string; var RTFConverter: TRichEdit; MyFileStream: TFileStream; begin RTFConverter := TRichEdit.CreateParented(HWND_MESSAGE); try // 正确读取RTF文件到流中 MyFileStream := TFileStream.Create(RTF_FilePath, fmOpenRead or fmShareDenyWrite); try RTFConverter.PlainText := False; // 确保以RTF模式加载内容 RTFConverter.Lines.LoadFromStream(MyFileStream); RTFConverter.PlainText := True; RTFConverter.Lines.StrictDelimiter := True; if ReplaceLineFeedWithSpace then RTFConverter.Lines.Delimiter := ' ' else RTFConverter.Lines.Delimiter := #13; Result := RTFConverter.Lines.DelimitedText; finally MyFileStream.Free; end; finally RTFConverter.Free; end; end;
三、不依赖带父窗口TRichEdit的高效方案
如果你不想使用CreateParented(HWND_MESSAGE)创建的RichEdit控件,可以直接调用Windows的RichEdit底层API处理,完全不依赖VCL控件封装,更轻量化:
function RtfToText_NoRichEdit(const RTF_FilePath: string; ReplaceLineFeedWithSpace: Boolean): string; var hRichEdit: HWND; StreamIn: EDITSTREAM; FileStream: TFileStream; Buffer: array[0..4095] of Char; function EditStreamCallback(dwCookie: DWORD_PTR; pbBuff: PByte; cb: LongInt; var pcb: LongInt): DWORD; stdcall; begin pcb := FileStream.Read(pbBuff^, cb); Result := 0; end; begin Result := ''; // 加载RichEdit库(这里使用RichEdit20W版本,兼容性较好) LoadLibrary('RICHED20.DLL'); // 创建无窗口的RichEdit实例 hRichEdit := CreateWindowEx(0, 'RICHEDIT20W', nil, ES_MULTILINE or ES_READONLY, 0, 0, 0, 0, HWND_MESSAGE, 0, HInstance, nil); if hRichEdit = 0 then Exit; try FileStream := TFileStream.Create(RTF_FilePath, fmOpenRead or fmShareDenyWrite); try // 设置流回调函数,将RTF文件内容读取到RichEdit中 StreamIn.dwCookie := DWORD_PTR(FileStream); StreamIn.pfnCallback := @EditStreamCallback; SendMessage(hRichEdit, EM_STREAMIN, SF_RTF, LPARAM(@StreamIn)); // 获取纯文本内容的长度 SetLength(Result, SendMessage(hRichEdit, WM_GETTEXTLENGTH, 0, 0) + 1); // 读取纯文本内容 SendMessage(hRichEdit, WM_GETTEXT, Length(Result), LPARAM(PChar(Result))); // 处理换行符替换需求 if ReplaceLineFeedWithSpace then Result := StringReplace(Result, #13#10, ' ', [rfReplaceAll]) else Result := StringReplace(Result, #10, '', [rfReplaceAll]); // 统一换行符为#13 finally FileStream.Free; end; finally DestroyWindow(hRichEdit); end; end;
这个方案直接调用底层API,没有VCL控件带来的额外开销,效率更高,也完全符合你“不使用带父窗口TRichEdit控件”的需求。如果想更简洁,也可以考虑使用开源的纯Pascal RTF解析类,但上述API方案已经足够高效且原生。
内容的提问来源于stack exchange,提问作者user1580348
相关产品推荐
相关产品推荐

