Trying to upload files bigger than 5 mb to Amazon S3
http://aws.amazon.com/articles/0006282245644577, here it is stated that
// The S3UploadInputStream was deprecated after the release of iOS6
Files under 5 mb I can easily upload over wifi with:
NSData *dataForAamzon = [[NSFileManager defaultManager] contentsAtPath:pathForFiile];
#try {
NSString *uploadName= #"somestring";
S3PutObjectRequest *por = [[S3PutObjectRequest alloc] initWithKey:uploadName
inBucket:[Constants userEventBucket]];
por.contentType = nil;
por.data = dataForAamzon;
// Put the image data into the specified s3 bucket and object.
S3PutObjectResponse *putObjectResponse = [self.s3 putObject:por];
[self performSelector:#selector(uploadAllFilesToAmazon:error:) withObject:nil withObject:putObjectResponse.error];
}
#catch ( AmazonServiceException *exception ) {
NSLog( #"Upload Failed, Reason: %#", exception );
}
Since S3UploadInputStream *stream was deprecated , how can I check if file is bigger than 5mb and use multipart upload in IOS 6 or later versions.
Thanks,
I hope you need to check the size of a local file exceeds 5MB right ?
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:_client.filename error:nil];
if(fileAttributes)
{
NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
long totalFileSize = [fileSizeNumber longLongValue];
if(totalFileSize > 5*1024*1024)
// Go for multipart upload
else
// Go for Direct Put request
}
Or from the NSData you can take the Length and perform the same calculation.
New release of AWS SDK solved my problem.
New AWS SDK is handling files size automatically you need to create trasnfer manager variable and delegate it to s3 object
something like
-(void) uploadAgendatoAmazon
{
//pass string in memory to nsdictionary
NSData * data = [_uploadPlistString dataUsingEncoding:NSUTF8StringEncoding];
NSString *uploadName= [NSString stringWithFormat:#"%#/%#/agenda.plist",[[NSUserDefaults standardUserDefaults] valueForKey:#"email"],self.textEventName.text];
self.s3.maxRetries = 10;
self.s3.timeout = 60;
self.tm = [S3TransferManager new];
self.tm.s3 = self.s3;
self.tm.operationQueue.maxConcurrentOperationCount = 2;
S3PutObjectRequest *por = [[S3PutObjectRequest alloc] initWithKey:uploadName
inBucket:[Constants userEventBucket]];
por.contentType = nil;
por.data = data;
por.delegate = self;
por.requestTag = #"uploadAgendatoAmazon";
// Put the image data into the specified s3 bucket and object.
[self.tm upload:por];
}
Here is the blog post for full details;
http://mobile.awsblog.com/post/TxIRFEQTW9XU8G/S3TransferManager-for-iOS-Part-I-Asynchronous-Uploads
Related
I am trying to add a feature to an existing iOS app so that documents "copied" within Mail (say a PDF) can be pasted into my app.
After a PDF document is viewed in Mail and "Copy" chosen from the Action menu, within my app's code, when I inspect:
[[UIPasteboard generalPasteboard] items]
I can see the document as per:
{
"com.adobe.pdf" = {length = 875113, bytes = 0x25504446 2d312e35 0d0a25b5 b5b5b50d ... 300d0a25 25454f46 };
}
)
And further retrieve it via:
po [[UIPasteboard generalPasteboard] valueForPasteboardType:#"com.adobe.pdf"]
<OS_dispatch_data: data[0x2820e5c00] = { leaf, size = 875113, buf = 0x1125e0000 }>
However, is there any way to get the document's name? In the Files.app when I paste the same document it gets pasted as the original file name.
Should I be using the pasteboard for this, or if there another API which can get access to the copied document with the file name?
Even if this question is a little older I happened to search for the same and finally found the solution. So for future reference:
Starting with iOS 11 UIPasteboard contains an array itemProviders which gives you all the information about the objects that are available. The same is used for Drag/Drop.
So with the following logic you can save the items to a certain path:
NSArray *items = [[UIPasteboard generalPasteboard] itemProviders];
for (NSInteger i = 0; i < itemProvider.count; i++) {
NSItemProvider *itemProvider = itemProvider[i];
NSString *identifier = itemProvider.registeredTypeIdentifiers[0];
[itemProvider loadDataRepresentationForTypeIdentifier:identifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) {
NSMutableDictionary *result;
if (!error) {
NSString *ext = (__bridge NSString *)(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(identifier), kUTTagClassFilenameExtension));
if ([ext isEqualToString:#"jpeg"]) {
ext = #"jpg";
}
NSString *mime = (__bridge NSString *)(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(identifier), kUTTagClassMIMEType));
if (!mime) {
mime = #"application/*";
}
NSString *filename = itemProvider.suggestedName;
NSString *path = [folderPath stringByAppendingPathComponent:filename];
[data writeToFile:path options:NSDataWritingAtomic error:&error];
}
}
}
i have a question about Keyboard Extension.
Container app has many images.(ex > 100 images and total 100MB)
and container app has saved using NSUserDefaults.
like this:
NSMutableArray* arr = [NSMutableArray new];
for(NSInteger i = 0; i < 100; i++)
{
UIImage* img = [UIImage imageNamed:[NSString stringWithFormat:#"img%ld",i]];
NSData* data = UIImagePNGRepresentation(image);
[arr addObject:data]
}
NSUserDefaults* ud = [[NSUserDefaults alloc] initWithSuiteName:#"<group identifier>"];
[ud setObject:arr forKey:#"image_data"];
[ud synchronize];
and keyboard app gets image data from NSUserDefaults.
Is it right way that container app send heavy size data to keyboard app?
In special case, when NSUserDefaults instance accesses method(objectForKey:) in keyboard app, keyboard app crashed.
The special case is :
if image data size in NSUserDefaults is bigger than about 30MB(not sure), keyboard app crashed and if the size is smaller than about 30MB, it works well.
Is there max size limit of NSUserDefaults?
i just want like this app.
i want to know that i control heavy size data in keyboard app.
1) First you have to write image in Shared document directory.
- (NSString *)getSharedLocationPath:(NSString *)appGroupName {
NSURL *groupContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.yourGroupName"];
return [groupContainerURL relativePath];
}
2) Write Image to above shared Directory.
NSString *path = [[self getSharedLocationPath:#"group.yourGroupName"] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#",images]];
//Here fileData is your Image data.
[fileData writeToFile:path atomically:YES];
3) Exactly get this path to Keyboard Extension class same as above.
- (NSString *)getSharedLocationPath:(NSString *)appGroupName {
NSURL *groupContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.yourGroupName"];
return [groupContainerURL relativePath];
}
//Here get content of directory from shared document directory.
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self getSharedLocationPath:#"group.yourGroupName"] error:NULL];
for (Count = 0; Count < (int)[directoryContent count]; Count++)
{
NSLog(#"File %d: %#", (Count + 1), [directoryContent objectAtIndex:Count]);
}
//Now you get your images from app shared directory.
Building for iOS 7+ ,
Building on Xcode 6.1 ,
Using Amazon SDK AWSiOSSDKv2 2.0.12 ,
Testing on iPhone 5s and iPad 2
I am downloading images from my Amazon S3 bucket with the Amazon SDK for iOS.
The downloading is working fine but I want to use the ifModifiedSince property to retrieve only images that have been modified since a certain date
(see http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSS3GetObjectRequest.html#//api/name/ifModifiedSince )
However, this is not working. Even when I specify a ifModifiedSince date that is LATER THAN the modified date of the file on S3, the file is returned.
According to the Amazon documentation:
ifModifiedSince -
Return the object only if it has been modified since the specified
time, otherwise return a 304 (not modified).
So I am not sure if I am doing something wrong or Amazon has a bug in the SDK.
Here is my code:
-(void)downloadPhotoWithName:(NSString*)name completed:(retrievedImage)completed {
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *cachePaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [cachePaths firstObject];
NSString *filename = [NSString stringWithFormat:#"%#.jpg", name];
NSString *filePath = [cacheDirectory stringByAppendingPathComponent:filename];
AWSS3 *transferManager = [AWSS3 defaultS3];
AWSS3GetObjectRequest *profilePhoto = [[AWSS3GetObjectRequest alloc] init];
profilePhoto.bucket = S3BUCKETNAMEIMAGE;
profilePhoto.key = filename;
if ([manager fileExistsAtPath:filePath isDirectory:NULL]) {
NSDictionary *att = [manager attributesOfItemAtPath:filePath error:nil];
if (att) {
//Get the date of when the file was modified so we can request to retrieve
//the file only if it was modified SINCE that date
NSDate *modifiedDate = [att objectForKey:NSFileModificationDate];
if (modifiedDate) {
profilePhoto.ifModifiedSince = modifiedDate;
}
}
}
[[transferManager getObject:profilePhoto] continueWithBlock:^id(BFTask *task) {
//If it was working we should get a 304 not the image file
if (task.result) {
AWSS3GetObjectOutput *output = (AWSS3GetObjectOutput*)task.result;
NSData *imageData = (NSData*)output.body;
if (imageData) {
NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys:output.lastModified, NSFileModificationDate, NULL];
//The log confirms that the date I am passing for ifModifiedSince is LATER THAN
//the last modified date of the file on S3
//but the the image file is returned anyway.. is it a problem with Amazon ?
NSLog(#"output.lastModified: %#\nmodifiedDate: %#", output.lastModified, profilePhoto.ifModifiedSince);
if ([manager createFileAtPath:filePath contents:imageData attributes:attr]) {
completed(imageData);
}
else {
NSLog(#"Could not save image to disk for some reason");
completed(nil);
}
}
else {
completed(nil);
}
}
else if (task.error) {
NSLog(#"DownloadPhotoError: %#", task.error);
completed(nil);
}
return nil;
}];
}
We've released the AWS Mobile SDK for iOS 2.0.14. It should address the time formatting issue.
I am trying to update an xml file. After suggestion I ended up choosing GdataXml.
So I am trying to update options.xml file.
Original File
<Dat>
<Name>Tom</Name>
<Option>1</Option>
</Dat>
I need to change "Tom" to "Jim" and save in the same file
Here is the code I tried.
-(void)saveToXML
{
NSString* path = [[NSBundle mainBundle] pathForResource:#"options" ofType:#"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:path];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
GDataXMLElement *rootElement = [GDataXMLElement elementWithName:#"Dat"];
NSArray *mySettings = [doc.rootElement elementsForName:#"Dat"];
for (GDataXMLElement *mySet in mySettings)
{
NSString *name;
NSArray *names = [mySet elementsForName:#"Name"];
if (names.count > 0)
{
GDataXMLElement *childElement = (GDataXMLElement *) [names objectAtIndex:0];
name = childElement.stringValue;
NSLog(childElement.stringValue);
[childElement setStringValue:#"Jim"];
}
}
[xmlData writeToFile:path atomically:YES];
}
But this is not updating options.xml file. Can some one help on this ?
The missing line of code you are looking for is
NSData *xmlData = doc.XMLData;
from Anupdas answer on your last question. You are currently reading a file into memory, initializing a new object using that memory, updating that new object and then writing the original file's memory into the new file location. So essentially you are reading a file and then writing the same file back to the file location.
Been trying to get this to work for a while know i have tried it with data and with streaming but with no luck, I assume i do not need to create the bucket as shown in most examples as the bucket i want to upload to already exists, also it tells me the bucket i am trying to access, however when i try to upload i get this
"Error uploading image to S3: The XML you provided was not well-formed or did not validate against our published schema"
here is the code
UIImage * img = [[[[CurrentGamesInfo sharedCurrentGamesInfo]GameInCreation] GetImageToSend]_imageToSend];
NSData *savedImageData = UIImageJPEGRepresentation(img, 0.8);
NSString *pictureName = [[[CurrentGamesInfo sharedCurrentGamesInfo]GameInCreation] GetGameID];
#try
{
AmazonS3Client *s3 = [[[AmazonS3Client alloc] initWithAccessKey:MY_ACCESS_KEY_ID withSecretKey:MY_SECRET_KEY] autorelease];
//[s3 createBucket:[[[S3CreateBucketRequest alloc] initWithName:MY_PICTURE_BUCKET] autorelease]];
NSArray *bucketArray = [s3 listBuckets];
S3Bucket *bucket = [[s3 listBuckets] objectAtIndex:0];
NSLog(#"%#",[bucket name]);
S3PutObjectRequest *por = [[[S3PutObjectRequest alloc] initWithKey:pictureName inBucket:MY_PICTURE_BUCKET] autorelease];
por.contentType = #"image/jpeg";
//por.data = savedImageData;
//por.cannedACL = [S3CannedACL publicRead];
S3UploadInputStream *stream = [S3UploadInputStream inputStreamWithData:savedImageData];
//stream.delay = 0.2;
//stream.packetSize = 16;
por.contentLength = [savedImageData length];
por.stream = stream;
[s3 putObject:por];
}
#catch (AmazonClientException *exception)
{
NSLog(#"Error uploading image to S3: %#", exception.message);
}
sooooo...what am i doing wrong?
Nevermind...the variable "pictureName" was nil...I slink away in shame