使用 Firebase Storage 的 putFile() 方法导致:无法打开文件“fileName”错误
Using Firebase Storage's putFile() method is resulting in: The file “fileName” couldn’t be opened error
以下是我尝试上传文件的两种方式:
1.
getURLOfPhoto(assetURL: imagesDictionary[String(whichProfileImage)]! , completionHandler: { (responseURL) in
FIRStorage.storage().reference().putFile(responseURL as! URL)
})
2.
let assets = PHAsset.fetchAssets(withALAssetURLs: [imagesDictionary[String(whichProfileImage)] as! URL], options: nil)
let asset = assets.firstObject
asset?.requestContentEditingInput(with: nil, completionHandler: { (contentEditingInput, info) in
let imageFile = contentEditingInput?.fullSizeImageURL?
FIRStorage.storage().reference().child("test").putFile(imageFile!, metadata: nil) { (metadata, error) in
if let error = error {
return
}
}
})
我收到这个错误:
Body file is unreachable: /var/mobile/Media/DCIM/100APPLE/picture.JPG
Error Domain=NSCocoaErrorDomain Code=257 "The file “picture.JPG” couldn’t be opened because you don’t have permission to view it."
UserInfo={NSURL=file:///var/mobile/Media/DCIM/100APPLE/picture.JPG, NSFilePath=/var/mobile/Media/DCIM/100APPLE/picture.JPG,
NSUnderlyingError=0x15da49a0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
URL 似乎已成功检索,错误仅在调用 putFile()
方法时发生。
有谁知道如何修复此错误或以其他方式将文件(不是数据对象)上传到 Firebase 存储?
提前致谢
由于应用沙盒的原因,我们的上传者可能没有正确的权限来访问该文件(我们非常犹豫是否授予广泛的文件系统访问权限)。
将文件存储在 Documents/
和 tmp/
中
当然,如果它来自系统资源,我们可能想要重新审视该行为。通常我只是这样做(是的,我知道它是 data
而不是 file
,因此会有更糟糕的内存行为):
// pragma mark - UIImagePickerDelegate overrides
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
// Get local image
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
let imageData = UIImagePNGRepresentation(image)!
// Get a reference to the location where we'll store our photos
let photosRef = storage.reference().child("chat_photos")
// Get a reference to store the file at chat_photos/<FILENAME>
let photoRef = photosRef.child("\(NSUUID().UUIDString).png")
// Upload file to Firebase Storage
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let text = snapshot.metadata?.downloadURL()?.absoluteString
}
// Clean up picker
dismissViewControllerAnimated(true, completion: nil)
}
目前 Firebase 存储无法使用文件 URLs,这些文件是使用我在问题中使用的基于 PHAsset 的代码检索的(或者至少根据我的经验它不能)——即使那些文件是用户自己用相机拍摄的文件iPhone。因此,一种解决方案是将有问题的文件重新保存到 Firebase 存储 API 可以访问的位置,然后通过将该位置的 URL 传入 putFile() 方法来上传文件.
如果您使用的是 imagePickerController() 方法,则可以使用此方法:
do {
let documentsURL = FileManager.default().urlsForDirectory(.documentDirectory,
inDomains: .userDomainMask)[0]
let fileURL = try documentsURL.appendingPathComponent("fileName.jpg")
let image = info[UIImagePickerControllerOriginalImage]
try UIImageJPEGRepresentation(image as! UIImage,1.0)?.write(to: fileURL, options: [])
FIRStorage.storage().reference().child("exampleLocation")
.putFile(fileURL, metadata: nil) { (metadata, error) in
if let error = error {
print("Error uploading: \(error.description)")
return
}
}
}
catch {
print("error is ", error)
}
@Mike McDonald,感谢您的回答,它对我有用。我遇到了完全相同的问题,并且能够根据您的建议解决。这是我的代码:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage else { return }
let profileImageName = "profileImageName.png"
let imageData = UIImagePNGRepresentation(image)!
let filePath = "\(FIRAuth.auth()!.currentUser!.uid)/\(Int(NSDate.timeIntervalSinceReferenceDate() * 1000))"
let photoStorageRef = FIRStorage.storage().reference().child(filePath)
let photoRef = photoStorageRef.child("\(profileImageName)")
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata) { metadata, error in
if let error = error {
print("Error uploading:\(error.localizedDescription)")
return
} else {
guard let downloadURL = metadata!.downloadURL() else { return }
guard let downloadURLString = metadata!.downloadURL()?.absoluteString else { return }
//do what I need to do with downloadURL
//do what I need to do with downloadURLString
}
}
希望这可以帮助遇到同样问题的其他人!
以下是我尝试上传文件的两种方式:
1.
getURLOfPhoto(assetURL: imagesDictionary[String(whichProfileImage)]! , completionHandler: { (responseURL) in
FIRStorage.storage().reference().putFile(responseURL as! URL)
})
2.
let assets = PHAsset.fetchAssets(withALAssetURLs: [imagesDictionary[String(whichProfileImage)] as! URL], options: nil)
let asset = assets.firstObject
asset?.requestContentEditingInput(with: nil, completionHandler: { (contentEditingInput, info) in
let imageFile = contentEditingInput?.fullSizeImageURL?
FIRStorage.storage().reference().child("test").putFile(imageFile!, metadata: nil) { (metadata, error) in
if let error = error {
return
}
}
})
我收到这个错误:
Body file is unreachable: /var/mobile/Media/DCIM/100APPLE/picture.JPG
Error Domain=NSCocoaErrorDomain Code=257 "The file “picture.JPG” couldn’t be opened because you don’t have permission to view it."
UserInfo={NSURL=file:///var/mobile/Media/DCIM/100APPLE/picture.JPG, NSFilePath=/var/mobile/Media/DCIM/100APPLE/picture.JPG,
NSUnderlyingError=0x15da49a0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
URL 似乎已成功检索,错误仅在调用 putFile()
方法时发生。
有谁知道如何修复此错误或以其他方式将文件(不是数据对象)上传到 Firebase 存储?
提前致谢
由于应用沙盒的原因,我们的上传者可能没有正确的权限来访问该文件(我们非常犹豫是否授予广泛的文件系统访问权限)。
将文件存储在Documents/
和 tmp/
中
当然,如果它来自系统资源,我们可能想要重新审视该行为。通常我只是这样做(是的,我知道它是 data
而不是 file
,因此会有更糟糕的内存行为):
// pragma mark - UIImagePickerDelegate overrides
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
// Get local image
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
let imageData = UIImagePNGRepresentation(image)!
// Get a reference to the location where we'll store our photos
let photosRef = storage.reference().child("chat_photos")
// Get a reference to store the file at chat_photos/<FILENAME>
let photoRef = photosRef.child("\(NSUUID().UUIDString).png")
// Upload file to Firebase Storage
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let text = snapshot.metadata?.downloadURL()?.absoluteString
}
// Clean up picker
dismissViewControllerAnimated(true, completion: nil)
}
目前 Firebase 存储无法使用文件 URLs,这些文件是使用我在问题中使用的基于 PHAsset 的代码检索的(或者至少根据我的经验它不能)——即使那些文件是用户自己用相机拍摄的文件iPhone。因此,一种解决方案是将有问题的文件重新保存到 Firebase 存储 API 可以访问的位置,然后通过将该位置的 URL 传入 putFile() 方法来上传文件.
如果您使用的是 imagePickerController() 方法,则可以使用此方法:
do {
let documentsURL = FileManager.default().urlsForDirectory(.documentDirectory,
inDomains: .userDomainMask)[0]
let fileURL = try documentsURL.appendingPathComponent("fileName.jpg")
let image = info[UIImagePickerControllerOriginalImage]
try UIImageJPEGRepresentation(image as! UIImage,1.0)?.write(to: fileURL, options: [])
FIRStorage.storage().reference().child("exampleLocation")
.putFile(fileURL, metadata: nil) { (metadata, error) in
if let error = error {
print("Error uploading: \(error.description)")
return
}
}
}
catch {
print("error is ", error)
}
@Mike McDonald,感谢您的回答,它对我有用。我遇到了完全相同的问题,并且能够根据您的建议解决。这是我的代码:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage else { return }
let profileImageName = "profileImageName.png"
let imageData = UIImagePNGRepresentation(image)!
let filePath = "\(FIRAuth.auth()!.currentUser!.uid)/\(Int(NSDate.timeIntervalSinceReferenceDate() * 1000))"
let photoStorageRef = FIRStorage.storage().reference().child(filePath)
let photoRef = photoStorageRef.child("\(profileImageName)")
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata) { metadata, error in
if let error = error {
print("Error uploading:\(error.localizedDescription)")
return
} else {
guard let downloadURL = metadata!.downloadURL() else { return }
guard let downloadURLString = metadata!.downloadURL()?.absoluteString else { return }
//do what I need to do with downloadURL
//do what I need to do with downloadURLString
}
}
希望这可以帮助遇到同样问题的其他人!