Exporting larger files lazarus / 43-Android ---------------------------------------------------------------------- Guser979 · 2025-07-08 21:55 In my app, I tried to export a 400 MB file using "savebytestouri," and the file was 0 bytes. When the file was 200 MB, it was written normally. This is due to the limitation of the array used: TDynArrayOfJByte. Solution: 1) Create an additional "AppendBytesToUri" method. 2) Use a function in your app that dynamically adjusts the array size until the entire file is written to user-accessible storage. 1) Add code in “androidwidget.pas”: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure AppendBytesToUri(_bytes: TDynArrayOfJByte; _toTreeUri: jObject);procedure jForm_AppendBytesToUri(env: PJNIEnv; _jform: JObject; _bytes: TDynArrayOfJByte; _toUri: jObject);  procedure  AppendBytesToUri(_bytes: TDynArrayOfJByte; _toTreeUri: jObject);begin  //in designing component state: set value here...  if FInitialized then     jForm_AppendBytesToUri(FjEnv, FjObject, _bytes ,_toTreeUri);end; procedure jForm_AppendBytesToUri(env: PJNIEnv; _jform: JObject; _bytes: TDynArrayOfJByte; _toUri: jObject);var  jParams: array[0..1] of jValue;  jMethod: jMethodID = nil;  jCls: jClass = nil;  byteArray: jByteArray;  len: SizeInt;label  _exceptionOcurred;begin  jCls := env^.GetObjectClass(env, _jform);  if jCls = nil then goto _exceptionOcurred;   jMethod := env^.GetMethodID(env, jCls, 'AppendBytesToUri', '([BLandroid/net/Uri;)V');  if jMethod = nil then goto _exceptionOcurred;   len := Length(_bytes);  byteArray := env^.NewByteArray(env, len);  env^.SetByteArrayRegion(env, byteArray, 0 , len, @_bytes[0]);   jParams[0].l := byteArray;  jParams[1].l := _toUri;   env^.CallVoidMethodA(env, _jform, jMethod, @jParams);  env^.DeleteLocalRef(env, jParams[0].l);  env^.DeleteLocalRef(env, jCls);    _exceptionOcurred: jni_ExceptionOccurred(env);end;    Add code in “jForm.java”: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i public void AppendBytesToUri(byte[] _bytes, Uri _toTreeUri) {    OutputStream out = null;    try {        out = controls.activity.getContentResolver().openOutputStream(_toTreeUri, "wa"); //   append mode        out.write(_bytes);        out.flush();    } catch (FileNotFoundException e) {        e.printStackTrace();    } catch (IOException e) {        e.printStackTrace();    } finally {      try {            if (out != null) out.close();        } catch (IOException e) {            e.printStackTrace();        }    }}        2) Usage example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  //In this  example  the app registers several photos that need to be exported.    // procedure export(arqname:string);// procedure AndroidModule1ActivityResult(Sender: TObject;requestCode: integer; resultCode: TAndroidResult; intentData: jObject);// function  StreamFileSmart(const FilePath: string; const Uri: jObject): Boolean;     //  var  zipnam :string; //Global var    // call export// zipnam:='fotos.zip' ; export (zipnam);     // Here a .zip file  (zipnam) is created with all the photos registered in the app and we invoke the file creation to obtain the uri procedure TAndroidModule1.export(arqname:string);       var zip: TZipper;i: Integer;relativefn,tmp: String;     begin      L := TStringList.Create ;FindAllFiles(L,GetEnvironmentDirectoryPath(dirDCIM), '*.jpg', true);                   zip := TZipper.Create;     try    zip.Filename := arqname;     try       for i:=0 to  L.Count-1    do begin                         if L[i] ='' then break;                          relativefn := CreateRelativePath(L[i],GetEnvironmentDirectoryPath(dirDownloads));         zip.Entries.AddFileEntry ( SysToUTF8(L[i]),extractfilename( l[i] ));      end;     finally      L.Free;    end;     zip.SaveToFile (GetEnvironmentDirectoryPath(dirDownloads)+'/'+arqname);     Self.Requ estCreateFile(Self.GetEnvironmentDirectoryPath(dirDownloads),'applicat ion/zip',arqname, 114);     finally    zip.Free;  end; end;                         // This is where we get the .zip file's uri and call the function to write the content. procedure TAndroidModule1.AndroidModule1ActivityResult(Sender: TObject;  requestCode: integer; resultCode: TAndroidResult; intentData: jObject);   begin        treeUri:= IntentManager1.GetDataUri(intentData);     if requestCode = 114 then  //create file     begin       Self.CopyFile(Self.GetEnvironmentDirect oryPath(dirDatabase)+'/'+zipnam,Self.GetEnvironmentDirectoryPath(dirDo wnloads)+'/'+zipnam );                                            Stre amFileSmart(GetEnvironmentDirectoryPath(dirDownloads)+'/'+zipnam,treeU ri);        end;    end;  // Here's the function that uses AppendBytesToUri for any file size. It sends a maximum of 200 MB and adjusts the array size if necessary.function  TAndroidModule1.StreamFileSmart(const FilePath: string; const Uri: jObject): Boolean;const  MAX_CHUNK = 200 * 1024 * 1024; var  fs: TFileStream;  buffer: array of byte;  jBuffer: TDynArrayOfJByte;  bytesRead, chunkSize: Integer;begin  Result := False;   if not FileExists(FilePath) then Exit;   try    fs := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite);    try    if fs.Size <= MAX_CHUNK then        chunkSize := fs.Size      else        chunkSize := MAX_CHUNK;       SetLength(buffer, chunkSize);    SetLength(jBuffer, chunkSize);       repeat        bytesRead := fs.Read(buffer[0], chunkSize);        if bytesRead > 0 then        begin                     Move(buffer[0], jBuffer[0], bytesRead);        SetLength(jBuffer, bytesRead);                   AppendBytesToUri( jBuffer, Uri);        end;      until bytesRead < chunkSize;       Result := True;    finally      fs.Free;    end;  except    on E: Exception do    begin      //  log error ou message             Result := False;    end;  end;end;                     // Credits : jmpessoa, neuro , ChatGpt