Jump to content


P4API.NET batch download file using GetFileContentEx()


  • Please log in to reply
1 reply to this topic

#1 laurent_tr

laurent_tr

    Member

  • Members
  • PipPip
  • 10 posts

Posted 16 July 2019 - 03:04 PM

Hello,

I want to use the GetFileContentEx() to download multiple files at once.
I have tested this with 2 scenarii,
1- Batch download text files only
2- Batch download text files and binary files (in my case the binary is a docx)

In the first case, the content of both text files are present in the API result but in the same string object with no clear separation in order for me to split them programmatically.
I have also tried leaving the file information in the result of GetFileContentEx() but the file information are separately stored at the head of result list.


In the second case, the result is in byte array and I cannot determine if the content of the demanded files are there or not, which makes it even harder to split the content of the two input files.

I would like to know if there is an option / a way to have GetFileContentEx() return the file content separately, each in an element of the result.

Following is my snippet of code to reproduce the test scenarii. In the attachment you can find the standard output of my 2 test scenarii.Attached File  TestPerforce-with-binary-files.txt   17.52K   5 downloads, Attached File  TestPerforce-without-binary-files.txt   935bytes   6 downloads
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Perforce.P4;
namespace TestPerforce
{
class Program
{
	 static void Main(string[] args)
	 {
		 // Test API
		 if (!Connect())
		 {
			 return;
		 }
		 LogProgress($"Connected to {ServerUri}.");
		 TestBatchDownloadFiles();
		 if (!Disconnect())
		 {
			 LogError("Could not disconnect from Perforce server.");
		 }
		 LogProgress("Disconnection succeeds.");
		 Console.WriteLine("Press any key to exit.");
		 Console.ReadKey();
	 }
	 private static string ServerUri = string.Empty;
	 private static string User = string.Empty;
	 private static string Password = string.Empty;
	 private static Repository P4Repository;
	 private static Connection P4Connection;
	 private static DateTime TicketExpirationTime;
	 private static IList<FileSpec>Files = new List<FileSpec>
	 {
		 new DepotPath("//test/root/limited_to_group1/helloworld.go"),
		 new DepotPath("//test/root/limited_to_group1/loop.go"),
		 new DepotPath("//test/root/limited_to_group1/text.docx"),
	 };
	 private static bool Connect()
	 {
		 // define the server, repository and connection
		 var server = new Server(new ServerAddress(ServerUri));
		 P4Repository = new Repository(server);
		 P4Connection = P4Repository.Connection;		 // use the connection variables for this connection
		 P4Connection.UserName = User;
		 P4Connection.Client = new Client();
		 var options = new Options();
		 options["ProgramName"] = "TestPerforceApi";
		 options["ProgramVersion"] = "2019.1.177.4442";		 // connect to the server
		 try
		 {
			 if (!P4Connection.Connect(options))
			 {
				 LogError($"Connect could not connect to Perforce server at {ServerUri}, with the user {User}.");
				 return false;
			 }
			 var credential = P4Connection.Login(Password);
			 TicketExpirationTime = credential.Expires;
			 LogProgress($"Connect obtains new validation ticket, valid until {TicketExpirationTime.ToString(CultureInfo.InvariantCulture)}.");
			 return true;
		 }
		 catch (Exception e)
		 {
			 LogException($"Connect could not connect to Perforce server at {ServerUri}, with the user {User}.", e);
			 return false;
		 }
	 }
	 private static bool Disconnect()
	 {
		 if (P4Connection != null)
		 {
			 P4Connection.Dispose();
			 P4Connection = null;
			 P4Repository = null;
		 }
		 return true;
	 }	

	 private static bool IsTicketExpired() => TicketExpirationTime == default || DateTime.UtcNow > TicketExpirationTime;
	
private static bool RefreshTicket()
	 {
		 if (P4Connection == null)
		 {
			 LogError("RefreshTicket there is no connection to refresh the authentication ticket.");
			 return false;
		 }
		 if (P4Connection.Status != ConnectionStatus.Connected)
		 {
			 LogError("RefreshTicket the connection is disconnected.");
			 return false;
		 }
		 var credential = P4Connection.Login(Password);
		 TicketExpirationTime = credential.Expires;
		 LogProgress($"RefreshTicket obtains new validation ticket, valid until {TicketExpirationTime.ToString(CultureInfo.InvariantCulture)}.");
		 return true;
	 }
	 private static bool TestBatchDownloadFiles()
	 {
		 LogProgress("Metadata");
		 // Get file metadata
		 {
			 var options = new GetFileMetaDataCmdOptions(
				 GetFileMetadataCmdFlags.FileSize,
				 null, null, 0, null, null, null);
			 var res = P4Repository.GetFileMetaData(Files, options);
			 for (var i = 0; i < res.Count; i++)
			 {
				 var metadata = res[i];
				 var sb = new StringBuilder()
					 .Append("File #").Append(i+1).Append(" ")
					 .Append("Name: ").Append(metadata.DepotPath.GetFileName()).Append(", ")
					 .Append("size: ").Append(metadata.FileSize).Append(", ")
					 .Append("modified: ").Append($"{metadata.HeadTime.ToString("yyyy/mm/dd", CultureInfo.InvariantCulture)}");
				 LogProgress(sb.ToString());
			 }
		 }
		 LogProgress("--------------------");
		 LogProgress("Content");
		 // Get file content
		 {
			 var options = new GetFileContentsCmdOptions(GetFileContentsCmdFlags.None, null);
			 var res = P4Repository.GetFileContentsEx(Files, options);
			 for (var i = 0; i < res.Count; i++)
			 {
				 LogProgress($"--- Element #{i+1}:");
				 var elem = res[i];
				 switch (elem)
				 {
					 case FileSpec spec:
						 LogProgress(spec.DepotPath.GetFileName());
						 break;
					 case string s:
						 LogProgress(s);
						 break;
					 case byte[] byteArray:
						 LogProgress(Encoding.Default.GetString(byteArray));
						 break;
				 }
			 }
		 }		 return true;
	 }
	 private static void LogProgress(string message) => Console.WriteLine(message);
	 private static void LogError(string message) => Console.WriteLine($"Error: {message}");
	 private static void LogException(string message, Exception ex) => Console.WriteLine($"Error: {message}, exception: {ex}");
}
}


#2 p4bill

p4bill

    Advanced Member

  • Members
  • PipPipPip
  • 202 posts

Posted 31 July 2019 - 07:16 PM

I don't think it is possible to get file content separately. The only way you'll be able to get it is to run GetFileContentsEx for each file. In your example code, if you look at P4Repository.Connection.LastResults.TextOutput you'll see the text from all of the files in one string. That is what we are getting from the P4API bridge as the TextResults for the command.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users