IOS NSURLSession后台上传如何在后台上传大文件?

IOS NSURLSession后台上传如何在后台上传大文件?,ios,nsurlsession,nsurlsessionuploadtask,Ios,Nsurlsession,Nsurlsessionuploadtask,我想上传2-3 GB的大文件(视频)到后台服务器,要求如下 第一种方法 如果internet连接丢失并重新连接,则应继续上载 即使应用程序处于后台,也应继续上载 如果用户终止应用程序并返回,则应继续上载 对于上述功能,我已经实现了什么 用户选择文件 将文件拆分为1MB的块,并将磁盘上的所有块保存为文件 针对每个区块文件创建上载任务,并在后台会话中添加该文件 上述方法有效,但在某些情况下失败 如果文件大于1GB,则在磁盘上创建块和写入块 抛出内存异常 如果我想上传1GB的文件,我需要额外的1GB空

我想上传2-3 GB的大文件(视频)到后台服务器,要求如下

第一种方法

  • 如果internet连接丢失并重新连接,则应继续上载

  • 即使应用程序处于后台,也应继续上载

  • 如果用户终止应用程序并返回,则应继续上载

  • 对于上述功能,我已经实现了什么

  • 用户选择文件

  • 将文件拆分为1MB的块,并将磁盘上的所有块保存为文件

  • 针对每个区块文件创建上载任务,并在后台会话中添加该文件

  • 上述方法有效,但在某些情况下失败

  • 如果文件大于1GB,则在磁盘上创建块和写入块 抛出内存异常

  • 如果我想上传1GB的文件,我需要额外的1GB空间来创建块

  • 第二种方法

    上载原始文件而不创建块,在这种情况下,如果网络连接丢失或用户杀死应用程序,我将无法继续上载

    我的问题是,在后台上传大文件的最佳方式是什么?记住所有这些要点

    我知道已经提出了一些这类问题,但没有一个能回答我的问题

    我花了很多时间来实现这一点,但无法成功实现。请帮助我或给出一些建议,什么是完成上述几点的最佳方式

    更新

    我使用下面的代码创建块 代码在Xamarin.IOS中,但如果有人在Objective C或Swift中提供解释,我可以

    public static void SplitFileInChunks( UploadFileInfo UploadFile )
    {
            int i = -1;
    
            long chunkSize = UploadHelper.chunkSize;
            nuint dataLength = (System.nuint)chunkSize; 
    
            //var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            string directoryPath = UploadHelper.UploadsDirectory;
    
            int chunkCount = 0;
            NSFileHandle fileHandleRead = NSFileHandle.OpenRead(UploadFile.FilePath);
    
            fileHandleRead.ReadInBackground();
            //fileHandleRead.WaitForDataInBackground();
    
            if (fileHandleRead == null)
                return;
    
            do
            {
                i++;
                ulong index = (ulong)(i * chunkSize);
    
                var filePath = Path.Combine(directoryPath, UploadFile.ContentGuide + "" + i.ToString());
                //fileHandleRead.SeekToFileOffset(index);
    
                NSData data = fileHandleRead.ReadDataOfLength(dataLength );
                Console.WriteLine(UploadFile.FileStatus);
    
                if (data.Length <= 0)
                    continue;
    
                NSFileManager.DefaultManager.CreateFile(filePath, data, attr: null);
    
    
                NSError error;
                //data.Save(filePath, true, out error);
    
                chunkCount++;
    
                Console.WriteLine("Data Lenght" + data.Length);
                data.Dispose();
                Console.WriteLine("Chunk " + i);
            }
    
            while ( i * chunkSize <= UploadFile.Size && UploadFile.FileStatus != UploadFileStatus.Aborted );
    
            fileHandleRead.CloseFile();
            fileHandleRead.Dispose();
    
            Console.WriteLine("All Files Written sucessuflly");
            UploadFile.TotalChunksCount = chunkCount;
    
        }
    
    publicstaticvoidsplitfileinchunks(UploadFileInfo-UploadFile)
    {
    int i=-1;
    long chunkSize=UploadHelper.chunkSize;
    nuint dataLength=(System.nuint)chunkSize;
    //var documents=Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    string directoryPath=UploadHelper.UploadsDirectory;
    int chunkCount=0;
    nsfilehandlefilehandleread=NSFileHandle.OpenRead(UploadFile.FilePath);
    fileHandleRead.ReadInBackground();
    //FileHandlerRead.WaitForDataInBackground();
    if(fileHandleRead==null)
    返回;
    做
    {
    i++;
    ulong指数=(ulong)(i*chunkSize);
    var filePath=Path.Combine(directoryPath,UploadFile.ContentGuide+“”+i.ToString());
    //fileHandleRead.SeekToFileOffset(索引);
    NSData data=FileHandlerRead.ReadDataOfLength(数据长度);
    WriteLine(UploadFile.FileStatus);
    
    如果(data.Length这肯定会起作用,但如果您控制另一端的软件,您可以做得更好:

    • 在服务器端:

      • 提供仅提供唯一ID的上载起始端点(URL)
      • 提供一个上载数据端点,该端点采用唯一ID、POST正文和可选的起始字节偏移量,并将数据写入服务器上的临时文件
      • 提供一个上载状态终结点,该终结点采用唯一ID并返回迄今为止存储在磁盘上的数据量
      • 提供上载完成的终结点
    • 在客户端:

      • 调用起始端点并获取上载的ID
      • 调用上载数据端点并开始发送数据
      • 失败时,调用上载状态端点以了解服务器实际获得的数据量
      • 然后调用数据端点并开始从该偏移量发送数据,告诉服务器您从何处开始。(在服务器上,始终从该偏移量开始将数据写入文件,即使从那时起长度增加了,只是为了安全。)
      • 完成后,调用upload finished端点

    这种体系结构还可以相当轻松地显示状态栏。

    是的,我使用的是后台会话,但为了在磁盘上保存块,我需要额外的空间,因为后台的NSURLsession只能与NSURL.FromFileName一起使用。据我所知,还有其他方法可以克服这一问题,如上载原始文件和支持恢复我曾尝试在Auto
    ReleasePool
    块中添加此功能,但这对我们来说并不幸运。不幸的是,除非您的数据完全适合RAM,否则我认为无法避免创建文件的截断副本。如果您预先对其进行分块,则可以创建当前分块的截断副本。无论如何,您的应用程序都必须是w确定并处理错误,然后重新启动传输。在某个时候,如果你的应用程序太频繁被唤醒,你将开始受到NSURLSession的惩罚,因此分块可能比不分块更糟糕。事实上,现在我想起来了,你可能可以使用基于流上载的NSURLSessionDownloadTask,但这取决于守护进程是否正确处理该问题。请首先尝试该方法,但如果失败,则必须创建文件的截断副本。我不明白第一种方法的含义,其次,我尝试使用此方法创建截断副本,但不幸的是,如果文件约为2-3 GB,并且我只上载了几次,则应用程序会崩溃t创建下载任务时,可以指定一个包含
    NSStream
    NSURLRequest
    对象。如果使用
    getBoundStreamsWithBufferSize:inputStream:outputStream:
    ,则应用程序可以控制提供正文数据。然后,每次从文件中读取几兆字节的数据,并将其写入输出流,并在创建
    NSURLRequest
    时传递输入流。基本上,在尝试发送数据之前打开流进行写入,等待获得“可用空间”事件,写入一些数据,并检查返回值以确定实际发送了多少数据。确保关闭