System.IO.IOException:使用后台时打开的文件太多NSUrlSessionUploadTask

时间:2018-03-15 18:07:06

标签: c# ios xamarin xamarin.ios

民间,

我的应用程序存在一个问题,该问题严重影响了该领域的用户,我需要一些帮助。对于上下文:现场用户接收工作票,并且必须在他们处理完票证后使用某些代码和信息对其进行响应。对于任何给定的响应,他们的公司可能需要上传图片(有时是图片)。当用户拍照时,它会保存到Environment.SpecialFolder.MyDocuments中的目录中。当用户从其图库中选择图片时,它/它们被提取为具有AssetResult属性的类Image的对象,然后使用此语句将其转换为NSDataNSData data = i.AsJPEG(new nfloat(0.8));,然后随后使用此语句保存:data.Save(picturesPath, true);

我正在使用标题中所述的NSUrlSession NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(string identifier)方法。包含NSUrlSession代码的代码文件名为UploadWrapper;我做了一个简单的UploadWrapper upload = new UploadWrapper("PolarisPicture")"PolarisPicture"作为会话标识符。

这是我的NSUrlSession配置和实例化的代码/构造函数:

    public UploadWrapper (string identifier)
    {
        using (var config = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(identifier))
        {
            config.HttpMaximumConnectionsPerHost = 10;
            config.TimeoutIntervalForRequest = 600.0;
            config.TimeoutIntervalForResource = 120.0;
            config.AllowsCellularAccess = true;
            bgSession = NSUrlSession.FromConfiguration(config, new UploadDelegate(), new NSOperationQueue());
        }
    }

以下是用于启动NSUrlSessionUploadTask的方法:

    public void PrepareUpload(string filename, string database, int num, string member, string org, string ticket, string locator, string folder)
    {
        try
        {
            Console.WriteLine("PrepareUpload called...");

            //var file = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PolarisPictures2/IMAGE.jpeg");
            Console.WriteLine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
            Console.WriteLine(filename);
            var boundary = "FileBoundary";
            string webApiAddress = "OURWEBAPI";
            NSUrl uploadHandleURL = NSUrl.FromString(webApiAddress);
            var bodyPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "BodyData" + num + ".tmp");
            NSMutableUrlRequest req = new NSMutableUrlRequest(uploadHandleURL);
            req.HttpMethod = "POST";
            req["Content-Type"] = "multipart/form-data; boundary=" + boundary;
            req["Filename"] = System.IO.Path.GetFileName(filename);
            req["database"] = database;
            req["folder"] = folder;
            req["member"] = member;
            req["org"] = org;
            req["ticket"] = ticket;
            req["locator"] = locator;
            Console.WriteLine(req["Filename"]);
            if (System.IO.File.Exists(bodyPath))
            {
                System.IO.File.Delete(bodyPath);
            }
            Console.WriteLine("Building the string...");
            StringBuilder sb = new StringBuilder("");
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"database\"\r\n\r\n");
            sb.Append(String.Format("{0}\r\n", database));                                     // Add database param
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"member\"\r\n\r\n");
            sb.Append(String.Format("{0}\r\n", member));                                       // Add member param
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"org\"\r\n\r\n");
            sb.Append(String.Format("{0}\r\n", org));                                          // Add org param
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"ticket\"\r\n\r\n");
            sb.Append(String.Format("{0}\r\n", ticket));                                       // Add ticket param
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"locator\"\r\n\r\n");
            sb.Append(String.Format("{0}\r\n", locator));                                      // Add locator param
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"folder\"\r\n\r\n");
            sb.Append(String.Format("{0}\r\n", folder));                                       // Add folder param
            sb.AppendFormat("--{0}\r\n", boundary);
            sb.AppendFormat("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"\r\n", System.IO.Path.GetFileName(filename));
            sb.Append("Content-Type: application/octetstream\r\n\r\n");
            var fileBytes = System.IO.File.ReadAllBytes(filename);
            using( var writeStream = new System.IO.FileStream(bodyPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read) )
            {
                writeStream.Write(Encoding.Default.GetBytes(sb.ToString()), 0, sb.Length);
                writeStream.Write(fileBytes, 0, fileBytes.Length);
                Console.WriteLine(sb.ToString());
                sb.Clear();
                sb.AppendFormat("\r\n--{0}--\r\n", boundary);
                writeStream.Write(Encoding.Default.GetBytes(sb.ToString()), 0, sb.Length);
                writeStream.Close();
                writeStream.Dispose();
            }
            sb = null;
            fileBytes = null;
            var uploadTask = bgSession.CreateUploadTask(req, NSUrl.FromFilename(bodyPath));
            uploadTask.TaskDescription = filename;
            Console.WriteLine($"New TaskID: {uploadTask.TaskIdentifier}");
            uploadTask.Resume();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

每次在foreach循环中调用此方法,该循环遍历当前附加的图片。完成此foreach后,将调用upload.Finish();,这只不过是调用基础NSUrlSession对象的FinishTasksAndInvalidate()方法:

            foreach (var att in currTick.Origin.GetAttachedFiles(currTick))
            {
                upload.PrepareUpload(att, info.Database, 0, currTick.Fields["Member"], currTick.Fields["Org"], currTick.Fields["Ticket"], info.FirstName + " " + info.LastName, folder);
                index = index + 1;
            }
            upload.Finish();

att是“附加”文件的路径。

最后,这是我的DidCompleteWithError()委托方法以及如果上传成功且没有错误则调用它的方法:

    public override void DidCompleteWithError(NSUrlSession session, NSUrlSessionTask task, NSError error)
    {
        Console.WriteLine(string.Format("DidCompleteWithError TaskId: {0}{1}", task.TaskIdentifier, (error == null ? "" : " Error: " + error.Description)));

        if (error == null)
        {
            Console.WriteLine("Deleting the picture copy since the upload succeeded");
            DeletePictureCopy(task.TaskDescription);
            task.Dispose();
        }
    }

DeletePictureCopy();用于删除图片的本地副本以节省空间:

    public void DeletePictureCopy(string path)
    {
        try
        {
            System.IO.File.Delete(path);
            Console.WriteLine("We deleted the copy of the picture successfully!");
        } catch( Exception ex )
        {
            Console.WriteLine(ex.ToString());
        }
    }

这里可能导致System.IO.IOException: Too many open files的原因是什么?这是每次PrepareUpload()方法都会出现的行:

var fileBytes = System.IO.File.ReadAllBytes(filename);(见上面的代码)

对于我的生活,我不能弄清楚为什么会这样。我甚至关闭用于写FileStream内部字节的using只是为了确保它被关闭。

用户上传3到4张图片后会出现此问题。我从来没有在第一张或第二张照片上遇到过这个问题。从不。

延迟后NSUrlSessionUploadTask关闭文件了吗?垃圾收集器是否未正确处理文件,即使在我手动完成后也是如此?

我无法找到解决方案,并希望得到任何帮助或指导。

感谢。

0 个答案:

没有答案