简体   繁体   中英

How can I write to a file using C++ buider in an Android app?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM