如何将视频文件保存到文档目录
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 - 视频文件数组可以很好地保存到应用程序库,但不能正确保存到应用程序文档目录