Three solutions for B / S uploading large files

Summarize the problems of large file fragment upload and breakpoint resume. Because the file is too large (such as more than 1G), you must consider the network interruption during the upload process. The HTTP network request itself already has a fragment upload function. When the transmitted file is relatively large, the HTTP protocol will automatically slice the file (block), but this is not the focus we are talking about now. What we need to do is Ensure that the part of the 1G file that has been uploaded after the network interruption does not need to be retransmitted the next time the network is connected. Therefore, when uploading locally, we must divide the large file into pieces, such as 1024 * 1024B, that is, divide the large file into 1M pieces for upload. After the server receives it, these pieces will be merged into the original file. The basic principle. Breakpoint resuming requires the local to record the status of each piece of upload. I marked it through three states (wait loading finish). When the network is interrupted, I will upload from the breakpoint after connecting again. The server judges whether the file has been completely uploaded by the file name and the total number of pieces.

        The details are as follows:

  1. First get the files (audio, video, pictures)

There are two cases, one is to get it directly in the album library, and the other is to call the camera. If it is obtained through UIImagePickerView (the details are not detailed, a lot of online), we will find that when you select a video, the compressed page of Figure 1 will appear, and finally the video obtained by our app is this compressed Video (not the original video in the video library, there is a note here, remember to release after operating the compressed video, the system will not release it for you, you need to manually operate, as will be described below), and then through -( Void ) imagePickerController :( UIImagePickerController  *) picker didFinishPickingMediaWithInfo :( NSDictionary  *) info in the protocol method

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 the type of selected file, such as KUTTypeImage, KUTTypeMovie. Note here the difference between movie and video, one is a video file with sound, one is a video file without sound, and of course, Audio is only sound without video. UIImagePickerControllerMediaURL is the URL of the video (if it was taken by the camera, then this is the original captured video; if it is selected in the album library, it is the video generated after compression). Note that this URL does not point to the album library. You can manipulate this video such as delete, copy, etc., you can get the size of the compressed video. UIImagePickerControllerReferenceURL is a URL pointing to the album. The official explanation is an NSURL that references an asset in the AssetsLibrary framework. Through this URL, you can get all the information of the video, including the file name, thumbnail, duration, etc. (through the assetsLibrary in ALAssetsLibrary assetForURL : referenceURL resultBlock :).

If it is taken by the camera, pay attention to two saving methods: save the picture to the album assetsLibrary writeImageDataToSavedPhotosAlbum : UIImageJPEGRepresentation ([info valueForKey : UIImagePickerControllerOriginalImage], (CGFloat) 1.0 ) metadata : nil completionBlock : failureBlock:

High-fidelity compression method NSData * UIImageJPEGRepresentation (UIImage * image, CGFloat compressionQuality)

Save the video to the album: assetsLibrary  writeVideoAtPathToSavedPhotosAlbum: MediaURL completionBlock: failureBlock:

 

Here, we have obtained all the required files and file information. The next thing to do is to split the file.

 

2. Fragment the obtained file

First, I save the obtained file in such a class

@interface CNFile : NSObject

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

the @Property  ( nonatomic , Copy ) NSString * filePath; // file in the app path

the @Property  ( nonatomic , Copy ) NSString * fileName; // filename

the @Property  ( nonatomic , ASSIGN ) NSInteger  fileSize; // File Size

@property (nonatomic, assign)  NSInteger  trunks; // Total number of pieces

@property (nonatomic,copy)NSString* fileInfo;

the @Property  ( nonatomic , strong ) UIImage * fileImage; // file thumbnails

@Property  ( nonatomic , strong ) NSMutableArray * fileArr; // tag upload status of each piece of

@end

So that we can operate on each CNFile object.

 

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

  How to get the total number of pieces:

    int  offset = 1024 * 1024 ; (the size of each slice is 1M)

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

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

    Divide the file and read the data of each piece:

    NSData* data;

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

    [readHandle seekToFileOffset:offset * chunk];

    data = [readHandle readDataOfLength:offset];

}

 

In this way, we obtain the data to be uploaded for each piece, and then ask the server whether the piece already exists

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

If it exists, make chunk + 1 and repeat the above method to read the next piece until the server does not exist, then upload the piece of data. In this method, pay attention to set the upload status of the chunk (wait loading finish), which will be related to the local judgment whether the file has been uploaded completely.

 

The next step is the upload process:

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

After the server returns that the piece has been uploaded successfully, we have many things to do:

1) First set the flag of the film that has been successfully uploaded to finish

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

 

2) to see if all the pieces of the flag have been placed finish, if already finishi, stating that the file upload is complete, then delete the file, upload a file or the end of the next.

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) If not all finish, then see if the flag used by the next chunk is wait

 NSLog (@ " Check the status of the first % ld piece ", chunk + 1 );

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

  {

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

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

             [me readDataWithChunk:ifileName:fileNamefile:file];

               break;

          }

   }

There can be a 2.5 between steps 2 and 3) to determine whether to suspend uploading

if(me.isPause ==YES)

  {

  // Save the first piece of the currently read few files to the local

     [self saveProgressWithChunk:chunk file:file];

      return ;

   }

This operation is actually the same as interrupting the network during the upload process. In order to resume the download at a breakpoint, we need to save the current progress when the network is disconnected or paused, so that we can skip the previous piece of finish in the next upload.

Then there is a problem. If we upload one piece at a time linearly, the meaning of piecewise upload is actually lost. We should combine multiple threads to make the piecewise upload process run concurrently and upload multiple pieces at the same time, which improves the upload efficiency. And make full use of network bandwidth.

    dispatch_async(dispatch_queue_t queue, ^{

        [me readDataWithChunk: chunk];

    })

Finally, pay attention to that, after uploading a video, go to the settings to see if the storage space occupied by your app has increased. If you do not deal with the generated compressed video, you will find that the space occupied by your app is very large. big.

Refer to this article for details: 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 / 
Welcome to the group to discuss together: 374992201

Guess you like

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