I'm using the community version of C++ builder (10.3) under Windows 10 to develop an app to run on a Samsung Galaxy A40.
One thing I can't seem to get working is saving the contents of TListBox to a file.
Being a newbie to Android, I'm not sure about where this file should appear and what rights I need.
I've tried the following in a function to save the contents of a listbox to a file, but can't seem to open a file to write to. It always returns -1:
int hFile; // File Handle
int ByteCt=0;
hFile = FileOpen("Shopping.lst", fmOpenWrite);
if (hFile > 0)
{
for (int i=0; i<ListBox1->Count; i++)
{
ByteCt+=FileWrite(hFile,ListBox1->Items[i].Text.c_str(),
ListBox1->Items->Strings[i].Length());
ByteCt+=FileWrite(hFile,"\n\r",2);
}
FileClose(hFile);
}
Is there something basic I've missed, or what?
Use the System::Ioutils::TPath
class to determine various system paths that your app can access. See Standard RTL Path Functions across the Supported Target Platforms for details. For example:
String FileName = TPath::Combine(TPath::GetDocumentsPath(), _D("Shopping.lst"));
hFile = FileOpen(FileName, fmOpenWrite);
// or: hFile = FileCreate(FileName);
But FYI, ListBox1->Items
is a TStrings
, which has its own SaveToFile()
method, eg:
ListBox1->Items->SaveToFile(FileName, TEncoding::UTF8);
You are just duplicating what SaveToFile()
already does for you. So you don't need to write the strings manually - especially since you are not even writing them correctly to begin with!
String
in C++Builder is an alias for UnicodeString
, which is a UTF-16 encoded string. Its Length()
specifies the number of WideChar
( char16_t
on Android) elements it contains, but FileWrite()
deals in raw bytes only. So you are writing only 1/2 of the bytes of each String
since sizeof(WideChar)=2
. And also, "\n\r"
is not a valid line break to use, either. You would need to use "\r\n"
or just "\n"
, or use the RTL's sLineBreak
global constant. But worse, you are trying to write the String
s in their original UTF-16 format but are writing the line breaks in an 8bit ANSI/UTF-8 format. So you end up with a mixed-encoding file, which many softwares won't be able to read correctly.
If you really want to write the String
s manually then it needs to look more like this instead:
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);
}
However, rather than using FileWrite()
directly, consider using TStreamWriter
instead, eg:
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));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.