如何将视频文件保存到文档目录

Posted

技术标签:

【中文标题】如何将视频文件保存到文档目录【英文标题】:how to save video file into document directory 【发布时间】:2011-08-02 17:49:40 【问题描述】:

我正在使用以下代码捕获视频:

UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType =  UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
//need to handle delegates methods 
//
ipc.allowsEditing = YES;
ipc.videoQuality = UIImagePickerControllerQualityTypeMedium;
ipc.videoMaximumDuration = 30.0f; // 30 seconds
//temporary duation of 30 seconds for testing

ipc.mediaTypes = [NSArray arrayWithObject:@"public.movie"];
// ipc.mediaTypes = [NSArray arrayWithObjects:@"public.movie", @"public.image", nil];
[self presentModalViewController:ipc animated:YES]; 
//this controller allows to record the videos

我可以使用以下代码将录制的视频保存到相册

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
 
    // recover video URL
    NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];

    // check if video is compatible with album
    BOOL compatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum([url path]);

    // save
    if (compatible)
        UISaveVideoAtPathToSavedPhotosAlbum([url path], self, @selector(video:didFinishSavingWithError:contextInfo:), NULL);
        NSLog(@"saved!!!! %@",[url path]);
    
    [self dismissModalViewControllerAnimated:YES];
    [picker release];

但我需要从相册中检索该文件并需要存储到文档目录中?

【问题讨论】:

您找到解决方案了吗? 【参考方案1】:

将视频保存到documents目录如下:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 

    NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
    NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *tempPath = [documentsDirectory stringByAppendingFormat:@"/vid1.mp4"];
    BOOL success = [videoData writeToFile:tempPath atomically:NO];
    [picker dismissModalViewControllerAnimated:YES];

【讨论】:

为什么 [videoData writeToFile:tempPath atomically:NO] 自动设置为 NO? 我也有一个后续问题。有没有办法保存视频但没有任何压缩?即按原样复制视频文件。 为什么保存为mp4?文件类型也可以是MOV吧?【参考方案2】:

如果将来有人需要,这里是 swift 代码:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) 

    let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
    let videoData = NSData(contentsOfURL: videoURL)
    let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
    let documentsDirectory: AnyObject = paths[0]
    let dataPath = documentsDirectory.stringByAppendingPathComponent("/vid1.mp4")

    videoData?.writeToFile(dataPath, atomically: false)
    self.dismissViewControllerAnimated(true, completion: nil)


【讨论】:

您也可以指定paths.first,其优点是如果列表长度为零,则不会失败。 如果有人遇到这个问题,你可以试试 videoData?.write(to: dataPath, options: .withoutOverwriting) .. 这对我有用。【参考方案3】:
#pragma mark -
#pragma mark File Names and Paths
// Creates the path if it does not exist.
- (void)ensurePathAt:(NSString *)path 
    NSFileManager *fm = [NSFileManager defaultManager];
    if ( [fm fileExistsAtPath:path] == false ) 
        [fm createDirectoryAtPath:path
      withIntermediateDirectories:YES
                       attributes:nil
                            error:NULL];
    

- (NSString *)documentPath 
    if ( ! documentPath_ ) 
        NSArray *searchPaths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        documentPath_ = [searchPaths objectAtIndex: 0];
        documentPath_=[documentPath_ stringByAppendingPathComponent:@"VideoAlbum"];
        [documentPath_ retain];
    
    return documentPath_;


- (NSString *)audioPath 
    if ( ! AudioPath_ ) 
        AudioPath_ = [[self documentPath] stringByAppendingPathComponent:@"Demo"];
        NSLog(@"%@",AudioPath_);
        [AudioPath_ retain];
        [self ensurePathAt:AudioPath_];
    
    return AudioPath_;

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

    NSString *type = [info objectForKey:UIImagePickerControllerMediaType];

    if ([type isEqualToString:(NSString *)kUTTypeVideo] || [type isEqualToString:(NSString *)kUTTypeMovie])
    
        NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];

        NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
        tempPath = [[self audioPath] stringByAppendingFormat:@"/%@.mp4",[NSDate date]];
        BOOL success = [videoData writeToFile:tempPath atomically:NO];

        NSLog(@"%hhd",success);
    
    [[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];

【讨论】:

【参考方案4】:

一点研发,这对我有用

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

 NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
  // Save video to app document directory

NSString *filePath = [url path];
NSString *pathExtension = [filePath pathExtension] ;
if ([pathExtension length] > 0)

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@", [filePath lastPathComponent]]];

   // Method last path component is used here, so that each video saved will get different name.

    NSError *error = nil ;
    BOOL res = [[NSFileManager defaultManager] moveItemAtPath:filePath toPath:localFilePath error:&error] ;

    if (!res)
    
        NSLog(@"%@", [error localizedDescription]) ;
    
    else
    
       NSLog(@"File saved at : %@",localFilePath);
    

//此外,当您必须检查应用文档目录中是否已经存在相同的视频并且您不想创建多个副本时,请进行如下更改

NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
NSURL *videoAsset = [info objectForKey:UIImagePickerControllerReferenceURL];

__weak typeof(self) weakSelf = self;

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:videoAsset resultBlock:^(ALAsset *asset)

    weakSelf.selectedFileName = [[asset defaultRepresentation] filename];
    NSLog(@"Video Filename %@",weakSelf.selectedFileName);

    // Save video to doc directory
    NSString *filePath = [url path];
    NSString *pathExtension = [filePath pathExtension] ;
    if ([pathExtension length] > 0)
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
        NSString *documentsDirectory = [paths objectAtIndex:0];

        NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@", weakSelf.selectedFileName]];

        //check if same video is having its copy in app directory.
        //so that multiple entries of same file should not happen.

        BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:localFilePath];

        if (!fileExists)
        
            NSError *error = nil ;

            BOOL res = [[NSFileManager defaultManager] moveItemAtPath:filePath toPath:localFilePath error:&error] ;

            if (!res)
            
                NSLog(@"%@", [error localizedDescription]) ;
            
            else
            
                NSLog(@"File saved at : %@",localFilePath);
                weakSelf.filePathURL = [NSURL URLWithString:localFilePath];
            
        
        else
        
            NSLog(@"File exist at : %@",localFilePath);
            weakSelf.filePathURL = [NSURL URLWithString:localFilePath];
        

    

//其中weakSelf.selectedFileName和weakSelf.filePathURL分别是我类的NSString和NSURL类型属性。

【讨论】:

唉,我相信 ALAssetsLibrary 已被弃用。我认为需要 phphoto。【参考方案5】:

我们可以使用 NSFileManager 的moveItemAtPath:toPath:error: 方法将视频文件移动到我们应用的文档目录中。效率更高。

我们还应该获取视频文件的扩展名并将其用作本地视频文件名的扩展名。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

    [self dismissViewControllerAnimated:YES completion:nil] ;

    if ([info[UIImagePickerControllerMediaType] isEqualToString:(NSString *)kUTTypeMovie]) 
        // video
        NSURL *url = [info[UIImagePickerControllerMediaType] ;
        NSString *filePath = [url path] ;
        NSString *pathExtension = [filePath pathExtension] ;
        if ([pathExtension length] > 0) 
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
            NSString *documentsDirectory = [paths objectAtIndex:0] ;
            NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"temp.%@", pathExtension]] ;
            NSError *error = nil ;
            BOOL res = [[NSFileManager defaultManager] moveItemAtPath:filePath toPath:localFilePath error:&error] ;
            if (!res) 
                NSLog(@"%@", [error localizedDescription]) ;
            
        
    

它对我有用。

【讨论】:

很好,对我也很好。 Swift 4.0 更新: let pathExtension = videoPath.pathExtension if !pathExtension.isEmpty, let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first let localFile = documentsDirectory.appendingPathComponent("temp.( pathExtension)").path do try FileManager.default.moveItem(atPath: videoPath.path, toPath: localFile) catch print("Cannot move the video (error)") 【参考方案6】:
 videoUrl = [info objectForKey:UIImagePickerControllerMediaURL];
urlString=[urlvideo path];
NSLog(@"path url %@",videoUrl);
NSData *videoData = [NSData dataWithContentsOfURL:videoUrl];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *sourcePath = [documentsDirectory stringByAppendingPathComponent:@"yourfilename.mp4"];

[videoData writeToFile:sourcePath atomically:YES];
//Below code will save video to ios Device
 ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:videoUrl
                            completionBlock:^(NSURL *assetURL, NSError *error)/*notify of completion*/];

[picker dismissViewControllerAnimated:YES completion:nil];

希望有帮助

【讨论】:

【参考方案7】:
    videoURL = info[UIImagePickerControllerMediaURL]as? NSURL
    print(videoURL!)

    let urlData=NSData(contentsOf: videoURL as! URL)

    if((urlData) != nil)
    
        let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        let documentDirectory = path.first! as NSString
        let fileName = "Video.MOV"
        let PDFPathFileName = documentDirectory.appendingPathComponent(fileName as String)

        print(PDFPathFileName)

        DispatchQueue.main.async( execute: 
            urlData?.write(toFile: PDFPathFileName, atomically: true)
        )

        do 
            let asset = AVURLAsset(url: videoURL as! URL , options: nil)
            let imgGenerator = AVAssetImageGenerator(asset: asset)
            imgGenerator.appliesPreferredTrackTransform = true
            let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(0, 1), actualTime: nil)
            let thumbnail = UIImage(cgImage: cgImage)
            imgView.image = thumbnail
            // thumbnail here

         catch let error 
            print("*** Error generating thumbnail: \(error.localizedDescription)")
        

    
    self.dismiss(animated: true, completion: nil)

【讨论】:

【参考方案8】:

斯威夫特 3/4

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
        // recover video URL
        let url = info[UIImagePickerControllerMediaURL] as? URL
        // check if video is compatible with album
        let compatible: Bool = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum((url?.path)!)
        // save
        if compatible 
            UISaveVideoAtPathToSavedPhotosAlbum((url?.path)!, self, nil, nil)
            print("saved!!!! \(String(describing: url?.path))")
        
        dismiss(animated: true, completion: nil)
    
//   error
    func video(_ videoPath: String, didFinishSavingWithError error: Error?, contextInfo: UnsafeMutableRawPointer) 
    

保存示例路径:-

"/private/var/mobile/Containers/Data/Application/EA53C844-7931-446C-800D-DA90717426BB/tmp/xxxxxx.MOV"

【讨论】:

【参考方案9】:

只要调用这个函数,它就会为你做每一件事:)

    private func saveVideo(url:URL) 
    DispatchQueue.global(qos: .userInitiated).async 
        guard let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else  return 
        if !FileManager.default.fileExists(atPath: documentsDirectoryURL.appendingPathComponent(url.lastPathComponent).path) 
            URLSession.shared.downloadTask(with: url)  (location, response, error) -> Void in
                guard let location = location else  return 
                let destinationURL = documentsDirectoryURL.appendingPathComponent(response?.suggestedFilename ?? url.lastPathComponent)

                do 
                    try FileManager.default.moveItem(at: location, to: destinationURL)
                    PHPhotoLibrary.requestAuthorization( (authorizationStatus: PHAuthorizationStatus) -> Void in
                        if authorizationStatus == .authorized 
                            PHPhotoLibrary.shared().performChanges(
                                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: destinationURL))  completed, error in
                                    DispatchQueue.main.async 
                                        if completed 
                                            self.view.makeToast(NSLocalizedString("Video Saved!", comment: "Video Saved!"), duration: 3.0, position: .center)
                                         else 
                                            print(error!)
                                        
                                    
                            
                        
                    )
                 catch  print(error) 

                .resume()
         else 
            print("File already exists at destination url")
        
    

【讨论】:

以上是关于如何将视频文件保存到文档目录的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 视频文件数组可以很好地保存到应用程序库,但不能正确保存到应用程序文档目录

如何将视频从应用程序文档目录移动到相机胶卷?

如何将 UIPickerViewController 中的图像或视频保存到文档目录?

如何将视频文件保存到自定义资源库?

快速视频到文档目录

如何获取保存在文档目录中的视频缩略图