Recent

Author Topic: Exporting larger files  (Read 753 times)

Guser979

  • Jr. Member
  • **
  • Posts: 69
Exporting larger files
« on: July 08, 2025, 11:55:04 pm »
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][+][-]
  1. procedure AppendBytesToUri(_bytes: TDynArrayOfJByte; _toTreeUri: jObject);
  2. procedure jForm_AppendBytesToUri(env: PJNIEnv; _jform: JObject; _bytes: TDynArrayOfJByte; _toUri: jObject);
  3.  
  4.  
  5. procedure  AppendBytesToUri(_bytes: TDynArrayOfJByte; _toTreeUri: jObject);
  6. begin
  7.   //in designing component state: set value here...
  8.   if FInitialized then
  9.      jForm_AppendBytesToUri(FjEnv, FjObject, _bytes ,_toTreeUri);
  10. end;
  11.  
  12. procedure jForm_AppendBytesToUri(env: PJNIEnv; _jform: JObject; _bytes: TDynArrayOfJByte; _toUri: jObject);
  13. var
  14.   jParams: array[0..1] of jValue;
  15.   jMethod: jMethodID = nil;
  16.   jCls: jClass = nil;
  17.   byteArray: jByteArray;
  18.   len: SizeInt;
  19. label
  20.   _exceptionOcurred;
  21. begin
  22.   jCls := env^.GetObjectClass(env, _jform);
  23.   if jCls = nil then goto _exceptionOcurred;
  24.  
  25.   jMethod := env^.GetMethodID(env, jCls, 'AppendBytesToUri', '([BLandroid/net/Uri;)V');
  26.   if jMethod = nil then goto _exceptionOcurred;
  27.  
  28.   len := Length(_bytes);
  29.   byteArray := env^.NewByteArray(env, len);
  30.   env^.SetByteArrayRegion(env, byteArray, 0 , len, @_bytes[0]);
  31.  
  32.   jParams[0].l := byteArray;
  33.   jParams[1].l := _toUri;
  34.  
  35.   env^.CallVoidMethodA(env, _jform, jMethod, @jParams);
  36.   env^.DeleteLocalRef(env, jParams[0].l);
  37.   env^.DeleteLocalRef(env, jCls);
  38.  
  39.   _exceptionOcurred: jni_ExceptionOccurred(env);
  40. end;
  41.  
  42.  
  43.  

Add code in “jForm.java”:

Code: Pascal  [Select][+][-]
  1. public void AppendBytesToUri(byte[] _bytes, Uri _toTreeUri) {
  2.     OutputStream out = null;
  3.     try {
  4.         out = controls.activity.getContentResolver().openOutputStream(_toTreeUri, "wa"); //   append mode
  5.         out.write(_bytes);
  6.         out.flush();
  7.     } catch (FileNotFoundException e) {
  8.         e.printStackTrace();
  9.     } catch (IOException e) {
  10.         e.printStackTrace();
  11.     } finally {
  12.         try {
  13.             if (out != null) out.close();
  14.         } catch (IOException e) {
  15.             e.printStackTrace();
  16.         }
  17.     }
  18. }      
  19.  
  20.  
  21.  



2)
Usage example:



Code: Pascal  [Select][+][-]
  1.  
  2. //In this  example  the app registers several photos that need to be exported.
  3.  
  4.  
  5.  
  6. // procedure export(arqname:string);
  7. // procedure AndroidModule1ActivityResult(Sender: TObject;requestCode: integer; resultCode: TAndroidResult; intentData: jObject);
  8. // function  StreamFileSmart(const FilePath: string; const Uri: jObject): Boolean;  
  9.  
  10.  
  11.  
  12. //  var  zipnam :string; //Global var  
  13.  
  14.  
  15. // call export
  16. // zipnam:='fotos.zip' ; export (zipnam);
  17.  
  18.  
  19.  
  20.  
  21.  // 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
  22.  procedure TAndroidModule1.export(arqname:string);
  23.    
  24.   var zip: TZipper;i: Integer;relativefn,tmp: String;
  25.    
  26.  begin
  27.    
  28.    L := TStringList.Create;FindAllFiles(L,GetEnvironmentDirectoryPath(dirDCIM), '*.jpg', true);
  29.                
  30.    zip := TZipper.Create;
  31.  
  32.  
  33.   try
  34.     zip.Filename := arqname;
  35.  
  36.     try
  37.  
  38.       for i:=0 to  L.Count-1    do begin
  39.          
  40.                   if L[i] ='' then break;
  41.        
  42.                   relativefn := CreateRelativePath(L[i],GetEnvironmentDirectoryPath(dirDownloads));
  43.  
  44.           zip.Entries.AddFileEntry ( SysToUTF8(L[i]),extractfilename( l[i] ));
  45.       end;
  46.  
  47.     finally
  48.       L.Free;
  49.     end;
  50.  
  51.     zip.SaveToFile(GetEnvironmentDirectoryPath(dirDownloads)+'/'+arqname);
  52.  
  53.     Self.RequestCreateFile(Self.GetEnvironmentDirectoryPath(dirDownloads),'application/zip',arqname, 114);
  54.  
  55.     finally
  56.     zip.Free;
  57.   end;
  58.  end;                        
  59.  
  60.  
  61. // This is where we get the .zip file's uri and call the function to write the content.
  62.  procedure TAndroidModule1.AndroidModule1ActivityResult(Sender: TObject;
  63.   requestCode: integer; resultCode: TAndroidResult; intentData: jObject);
  64.  
  65.  
  66.  begin
  67.         treeUri:= IntentManager1.GetDataUri(intentData);
  68.  
  69.     if requestCode = 114 then  //create file
  70.      begin
  71.  
  72.       Self.CopyFile(Self.GetEnvironmentDirectoryPath(dirDatabase)+'/'+zipnam,Self.GetEnvironmentDirectoryPath(dirDownloads)+'/'+zipnam );                                      
  73.       StreamFileSmart(GetEnvironmentDirectoryPath(dirDownloads)+'/'+zipnam,treeUri);
  74.         end;
  75.  
  76.   end;
  77.  
  78.  
  79. // 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.
  80. function  TAndroidModule1.StreamFileSmart(const FilePath: string; const Uri: jObject): Boolean;
  81. const
  82.   MAX_CHUNK = 200 * 1024 * 1024;
  83. var
  84.   fs: TFileStream;
  85.   buffer: array of byte;
  86.   jBuffer: TDynArrayOfJByte;
  87.   bytesRead, chunkSize: Integer;
  88. begin
  89.   Result := False;
  90.  
  91.   if not FileExists(FilePath) then Exit;
  92.  
  93.   try
  94.     fs := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite);
  95.     try
  96.       if fs.Size <= MAX_CHUNK then
  97.         chunkSize := fs.Size
  98.       else
  99.         chunkSize := MAX_CHUNK;
  100.  
  101.       SetLength(buffer, chunkSize);
  102.       SetLength(jBuffer, chunkSize);
  103.  
  104.       repeat
  105.         bytesRead := fs.Read(buffer[0], chunkSize);
  106.         if bytesRead > 0 then
  107.         begin
  108.            
  109.           Move(buffer[0], jBuffer[0], bytesRead);
  110.           SetLength(jBuffer, bytesRead);
  111.  
  112.            
  113.        AppendBytesToUri( jBuffer, Uri);
  114.         end;
  115.       until bytesRead < chunkSize;
  116.  
  117.       Result := True;
  118.     finally
  119.       fs.Free;
  120.     end;
  121.   except
  122.     on E: Exception do
  123.     begin
  124.       //  log error ou message
  125.        
  126.       Result := False;
  127.     end;
  128.   end;
  129. end;                      
  130.  
  131.  
  132.  



// Credits : jmpessoa, neuro , ChatGpt

 

TinyPortal © 2005-2018