ASP.NET realize uploading and downloading large files

To summarize large file fragmentation problem and resume broken uploads. Because the file is too large (such as 1G or more), you must consider the case of a network outage upload process. Network http request in itself already has a fragment upload function when the file transfer is relatively large, http protocols automatically moves the file sections (block), but this is not what we are talking about focus, we need to do is 1G ensure that part of the file after a network outage has been uploaded without having to retransmit the next time a network connection. So when we upload local, to large files to be fragmented, for example, is divided into 1024 * 1024B, is about large file into pieces 1M upload, server receives, and then combine these pieces into the original file, which is fragmented the basic principle. HTTP requires local upload to record the state of each piece, I tagged (wait loading finish) through three states, when network outages, connected again, upload from the breakpoint. Server by the file name, the total number of tablets to determine whether the file has finished uploading all.

        The following is the details:

  1, first get the file (audio and video, pictures)

Two cases, one is directly in the album library, one is calling camera. If it is to get (the details are not described in detail, a lot of the Internet) by UIImagePickerView, we will find that when you select a video, there will be compressed page of Figure 1, and finally we get the app is this video after compression video (not a video library of original video, there is a note that point, after you remember the operation of the compressed video release, the system will not help you release, you need to manually operate, we will discuss below), then by the UIImagePickerView protocol method - (void) imagePickerController: (UIImagePickerController *) picker didFinishPickingMediaWithInfo: (NSDictionary *) info get video info

fileInfo = {

    UIImagePickerControllerMediaType = "public.movie";

    UIImagePickerControllerMediaURL = "file:///private/var/mobile/Containers/Data/Application/2AAE9E44-0E6D-4499-9AC3-93D44D8342EA/tmp/trim.F36EC46C-4219-43C8-96A7-FA7141AB64D2.MOV";

    UIImagePickerControllerReferenceURL = "assets-library://asset/asset.MOV?id=DEDA9406-3223-4F87-ABB2-98FB5F5EB9C4&ext=MOV";

}

UIImagePickerControllerMediaType is selected file types, such as KUTTypeImage, KUTTypeMovie. Here note the difference between movie and video, and there is a sound of video file, a video file is no sound, of course, is only Audio sound no video. UIImagePickerControllerMediaURL is the URL of the video (if a camera, then this is the original captured by video; if it is selected in the album library, video compression that is generated after). Notice that the URL does not point to an album library, through this URL you can operate the video such as delete, copy, etc., you can get the size of the compressed video. UIImagePickerControllerReferenceURL is a pointer to the album URL, the official explanation is that an NSURL all the information that references an asset in the AssetsLibrary framework, through this URL, you can get the video, including the file name, thumbnail, duration, etc. (by ALAssetsLibrary in the assetsLibraryassetForURL : referenceURLresultBlock :).

如果是相机拍摄的,注意两个保存方法:图片保存到相册assetsLibrarywriteImageDataToSavedPhotosAlbum:UIImageJPEGRepresentation([infovalueForKey:UIImagePickerControllerOriginalImage],(CGFloat)1.0)metadata:nilcompletionBlock: failureBlock:

高保真压缩图片的方法NSData * UIImageJPEGRepresentation ( UIImage *image, CGFloat compressionQuality)

视频保存到相册:assetsLibrary writeVideoAtPathToSavedPhotosAlbum:MediaURL completionBlock:failureBlock:

 

到这里,我们就获取了所有需要的文件以及文件信息。下面要做的就是将文件分片。

 

2、将获取到的文件分片

首先,我将获取到的文件保存在这这样一个类中

@interface CNFile : NSObject

@property (nonatomic,copy)NSString* fileType;//image  or  movie

@property (nonatomic,copy)NSString* filePath;//文件在app中路径

@property (nonatomic,copy)NSString* fileName;//文件名

@property (nonatomic,assign)NSInteger fileSize;//文件大小

@property (nonatomic,assign) NSInteger trunks;//总片数

@property (nonatomic,copy)NSString* fileInfo;

@property (nonatomic,strong)UIImage* fileImage;//文件缩略图

@property (nonatomic,strong) NSMutableArray* fileArr;//标记每片的上传状态

@end

这样我们就可以对每一个CNFile对象进行操作了。

 

-(void)readDataWithChunk:(NSInteger)chunk file:(CNFile*)file{

  总片数的获取方法:

    int offset =1024*1024;(每一片的大小是1M)

    NSInteger chunks = (file.fileSize%1024==0)?((int)(file.fileSize/1024*1024)):((int)(file.fileSize/(1024*1024) + 1));

    NSLog(@"chunks = %ld",(long)chunks);

    将文件分片,读取每一片的数据:

    NSData* data;

    NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:file.filePath];

    [readHandle seekToFileOffset:offset * chunk];

    data = [readHandle readDataOfLength:offset];

}

 

这样我们就获取了每一片要上传的数据,然后询问服务器,该片是否已经存在

(方法-(void)ifHaveData:(NSData*)data WithChunk:(NSInteger)chunk file:(CNFile*)file)

,如果存在,令chunk+1,重复上面的方法读取下一片,直到服务器不存在该片,那么上传该片数据。在这个方法中注意设置该chunk的上传状态(wait  loading finish),这将关系到本地判断该文件是否已全部上传完成。

 

下一步就是上传的过程:

-(void)uploadData:(NSData*) data WithChunk:(NSInteger) chunk file:(CNFile*)file;

在服务器返回该片上传成功后,我们要做的事有很多:

1)先将已经成功上传的本片的flag置finish

[file.fileArr replaceObjectAtIndex:chunk withObject:@“finish"];

 

2)查看是否所有片的flag都已经置finish,如果都已经finishi,说明该文件上传完成,那么删除该文件,上传下一个文件或者结束。

for (NSInteger j =0; j<chunks; j++){

if (j == chunks || ((j == chunks -1)&&([file.fileArr[j]isEqualToString:@"finish"])))

     [me deleteFile:file.filePath];

     [me readNextFile];

}

3)如果没有都finish,那么看本地下一chunk对用的flag是否是wait

 NSLog(@"查看第%ld片的状态",chunk+1);

 for(NSInteger i = chunk+1;i < chunks;i++)

  {

     NSString* flag = [file.fileArrobjectAtIndex:i];

      if ([flagisEqualToString:@"wait"]) {

             [me readDataWithChunk:ifileName:fileNamefile:file];

               break;

          }

   }

在第2、3步之间可以有一个 2.5)判断是否暂停上传

if(me.isPause ==YES)

  {

  //将目前读到了第几个文件的第几片保存到本地

     [self saveProgressWithChunk:chunk file:file];

      return ;

   }

这个操作实际上和上传过程中断网是一样的,为了断点续传,在断网或者暂停的时候,我们要将目前的进度保存起来,以便下次上传时略过前面已置finish的片。

然后还有一个问题,如果我们就这样线性的一片一片上传,实际上失去了分片上传的意义,应该结合多线程,使分片上传过程并发执行,同时上传多片,这样就提高了上传效率,并充分利用了网络带宽。

    dispatch_async(dispatch_queue_t queue, ^{

        [me readDataWithChunk: chunk];

    })

最后注意一下,每上传完一个视频,去设置里看看你的app占用的存储空间有没有增大哦,如果你没有处理那个生成的压缩视频,你会发现你的app的空间占用量是很大的。

详细参考这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/%e5%a4%a7%e6%96%87%e4%bb%b6%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0-2/

Guess you like

Origin www.cnblogs.com/songsu/p/11525529.html