Search code examples
delphifiremonkey

How to create a folder and a txt file in Delphi


How do I create a new folder in the internal storage (?) of Android (I want say, the main folder that has all the subfolders ... Whatsapp, DCIM, pictures, Ringtones, Alarms ..) and create a new .txt file inside in this folder.

I want to create a .txt file and I need the user to plug the USB cable into their computer, access the device, enter the folder my application creates, and copy this file to their desktop.

I tried this code to create the file:

procedure TF_start.Button2Click(Sender: TObject);
var
  output_text: string;
  arquivo: TextFile;
begin
  output_text := 'test';

  TFile.WriteAllText(TPath.Combine(TPath.GetDocumentsPath, 'test.txt'), 'content');

  ReWrite(arquivo);

  WriteLn(arquivo, output_text);

  CloseFile(arquivo);

end;

But it does not work.

To get the internal storage(?) path, I found this code:

P := '/storage/';
if (FindFirst(P + '*', faAnyFile, Sr) = 0) then
  repeat
    Memo1.Lines.Add(Sr.Name);
  until (FindNext(Sr) <> 0);
FindClose(Sr);

But I can't understand how it works, so I can't even use it.

I also found this link, but I didn't find any function that returns me the "general" directory path I want to create a folder.

The functions System.IOUtils.TPath.GetHomePath(), and System.IOUtils.TPath.GetDocumentsPath() do not return me the correct path.

System.SysUtils.GetHomePath() return -> /data/user/0/com.embarcadero.app/cache

System.IOUtils.TPath.GetDocumentsPath() return -> /data/com.embarcadero.app-1/lib/arm

@edit

Using the @Remy Lebeau code and this code I managed to get to this point. The problem is that the code to update the directory with the files does nothing

Use System.IOUtils, Androidapi.Helpers, Androidapi.Jni.Media, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText;

//Button

procedure TF_start.Button2Click(Sender: TObject);
var
  path_file output_text: string;
begin
  path_file := TPath.Combine(System.IOUtils.TPath.GetSharedDownloadsPath, 'Folder_app');
  output_text := 'test';
  if not TDirectory.Exists(path_file) then
    TDirectory.CreateDirectory(path_file);

  try
    TFile.WriteAllText(TPath.Combine(path_file, Nome_Arquivo), Arquivo_saida);
  except
    ShowMessage('An error occurred while saving the file.');
  end;
end;

Another button:

procedure TF_corrida.BTNfinalize_appClick(Sender: TObject);
var
  c: Integer;
  JMediaScannerCon: Androidapi.Jni.Media.JMediaScannerConnection;
  JMediaScannerCon_Client: Androidapi.Jni.Media.JMediaScannerConnection_MediaScannerConnectionClient;
begin
    JMediaScannerCon:=TJMediaScannerConnection.JavaClass.init(TAndroidHelper.Context, JMediaScannerCon_Client);
    JMediaScannerCon.connect;
    c:=0;
    while not JMediaScannerCon.isConnected do begin
      Sleep(100);
      inc(c);
      if (c>20) then break;
    end;
    if (JMediaScannerCon.isConnected) then begin
      JMediaScannerCon.scanFile(StringToJString(path_file), nil);
      JMediaScannerCon.disconnect;
    end;
end;

PS This warning had appeared:

[DCC Warning] u_corrida.pas(682): W1000 Symbol 'SharedActivityContext' is deprecated: 'Use TAndroidHelper.Context'

So I changed the code

Note: I also tried replacing "path_file" with "System.IOUtils.TPath.GetSharedDownloadsPath", but to no avail too

This question has already been answered, the other question (index files and folders) has been moved to: How to index a created file in Android sdcard Delphi


Solution

  • You don't actually want "internal storage", that is private to your app and not even the user can access it (without root access to the device). You want "external storage" instead, so the user (and other apps) can access it.

    Per Save files on device storage in Android's documentation:

    Internal storage is best when you want to be sure that neither the user nor other apps can access your files.

    External storage is the best place for files that don't require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.

    Use one of the TPath.GetShared...() methods to get an "external storage" path, such as TPath.GetSharedDocumentsPath(). And make sure your app has the WRITE_EXTERNAL_STORAGE permission enabled.

    Also, note that TFile.WriteAllText() will not create a missing folder (in fact, it will raise an EDirectoryNotFoundException). You have to create the folder yourself first, such as with TDirectory.CreateDirectory() or SysUtils.ForceDirectories(). TPath.Combine() simply concatenates the input strings together, it does not create the actual folder.

    Try this:

    procedure TF_start.Button2Click(Sender: TObject);
    var
      path, output_text: string;
    begin
      output_text := 'test';
      path := TPath.Combine(TPath.GetSharedDocumentsPath, 'myfolder');
      if not TDirectory.Exists(path) then
        TDirectory.CreateDirectory(path);
      TFile.WriteAllText(TPath.Combine(path, 'test.txt'), output_text);
    end;