使用System::Ioutils::TPath
该类来确定您的应用可以访问的各种系统路径。有关详细信息,请参阅跨受支持目标平台的标准 RTL 路径函数。例如:
String FileName = TPath::Combine(TPath::GetDocumentsPath(), _D("Shopping.lst"));
hFile = FileOpen(FileName, fmOpenWrite);
// or: hFile = FileCreate(FileName);
但仅供参考,ListBox1->Items
是 a TStrings
,它有自己的SaveToFile()
方法,例如:
ListBox1->Items->SaveToFile(FileName, TEncoding::UTF8);
你只是在复制SaveToFile()
已经为你做的事情。因此,您不需要手动编写字符串 - 特别是因为您甚至没有正确编写它们!
String
在 C++Builder 中是 的别名UnicodeString
,它是一个 UTF-16 编码的字符串。它Length()
指定它包含的WideChar
(char16_t
在 Android 上)元素的数量,但FileWrite()
仅处理原始字节。所以你只写了每个的 1/2 字节,String
因为sizeof(WideChar)=2
. 而且,"\n\r"
也不是一个有效的换行符。您需要使用"\r\n"
or just "\n"
,或使用 RTL 的sLineBreak
全局常量。但更糟糕的是,您试图以String
原始 UTF-16 格式编写 s,但以 8 位 ANSI/UTF-8 格式编写换行符。因此,您最终会得到一个混合编码文件,许多软件将无法正确读取该文件。
如果您真的想String
手动编写 s ,那么它需要看起来更像这样:
int hFile; // File Handle
int ByteCt=0, BytesWritten;
hFile = FileOpen(FileName, fmOpenWrite);
// or: hFile = FileCreate(FileName);
if (hFile > 0)
{
for (int i=0; i < ListBox1->Count; i++)
{
String s = ListBox1->Items->Strings[i];
BytesWritten = FileWrite(hFile, s.c_str(), s.Length() * sizeof(WideChar));
if (BytesWritten < 0) break;
ByteCt += BytesWritten;
BytesWritten = FileWrite(hFile, _D("\r\n"), sizeof(WideChar) * 2);
if (BytesWritten < 0) break;
ByteCt += BytesWritten;
/* alternatively:
UTF8String s = ListBox1->Items->Strings[i];
BytesWritten = FileWrite(hFile, s.c_str(), s.Length());
if (BytesWritten < 0) break;
ByteCt += BytesWritten;
BytesWritten = FileWrite(hFile, "\r\n", 2);
if (BytesWritten < 0) break;
ByteCt += BytesWritten;
*/
}
FileClose(hFile);
}
但是,不要FileWrite()
直接使用,而是考虑使用TStreamWriter
,例如:
int ByteCt=0;
std::unique_ptr<TStreamWriter> File(new TStreamWriter(FileName, TEncoding::UTF8));
// or: auto File = std::make_unique<TStreamWriter>(FileName, TEncoding::UTF8);
for (int i=0; i < ListBox1->Count; i++)
{
String s = ListBox1->Items->Strings[i];
File->WriteLine(s);
ByteCt += (File->Encoding->GetByteCount(s) + File->Encoding->GetByteCount(File->NewLine));
}