I'm using that code to save downloaded videos from internet to application document folder:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *save_it = [documentsDirectory stringByAppendingPathComponent:video_filename];
NSError *error;
BOOL success = [fileData writeToFile:save_it options:0 error:&error];
if (!success) {
NSLog(#"writeToFile failed with error %#", error);
}
it works, but if there is a slash "/" in the video_filename it breaks because of slash is directory seperator, I know.
For example when video_filename is : Best Video / Best Song Ever.3gpp , log says:
{NSFilePath=/Users/Apple/Library/Developer/CoreSimulator/Devices/5A7D36F5-6EDB-495D-9E8E-B9EB22E5357C/data/Containers/Data/Application/B1D0AC48-D84C-4A0D-9F09-08BF4C45DD32/Documents/Best Video / Best Song Ever.3gpp, NSUnderlyingError=0x7d339430 "The operation couldn’t be completed. No such file or directory"}
I don't know is there any other special character that will make crashing,
So what is the best way of cleaning these special characters from nsstring ?
We can make SEO friendly urls in PHP, I'm searching a function like that to do this.
The first problem I see here is that your file path includes some spaces. in the example you gave, the value of video_filename variable is "Best Video / Best Song Ever.3gpp" which includes spaces around the slash. You first have to delete the spaces, this might help you do that:
NSArray *components = [video_filename componentsSeparatedByString:#"/"];
for (NSInteger i = 0, i < components.count, ++i) {
NSString *string = components[i];
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
components[i] = string;
}
NSString *path = [components componentsJoinedByString:#"/"];
If I understood correctly, your video_filename might be either in the form xxx.3gpp or yyy/xxx.3gpp. If it's the format of yyyy/xxxx.3gpp, you first have to create a directory named yyyy and then save the file to that directory.
This might help you do that:
- (void)createDirectory:(NSString *)directoryName
atFilePath:(NSString *)filePath
{
NSString *filePathAndDir = [filePath
stringByAppendingPathComponent:directoryName];
NSError *error;
if (![[NSFileManager defaultManager] createDirectoryAtPath:filePathAndDir
withIntermediateDirectories:NO
attributes:nil
error:&error]) {
NSLog(#"Create directory error: %#", error);
}
}
and the way you would use this is
[self createDirectory:components[0] atFilePath:documentsDirectory];
hope this helps!
So if your filename is actually "Best Video / Best Song Ever.3gpp" I am sorry but nothing easy comes to mind.
Now if Best Video is a folder where you will save your file you can use :
+(NSString*) getPathToFolder:(NSString*) folderName {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *folderPath = [documentsPath stringByAppendingPathComponent:folderName];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:folderPath]) {
NSLog(#"Creating a new folder at\n%#", folderPath) ;
[fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:NO attributes:nil error:nil];
}
return folderPath ;
}
This will check if your folder exist or not, if it does not exists then it will create it.
it will return the path you will want to use to save your file.
Now regarding the naming of the files, using spaces is highly unadvisable, I suggest using :
NSString* pathWITHSpaces ;
NSString* pathWithoutSpaces = [pathWITHSpaces stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
Hope this helps a bit
Related
I am creating an application. I am storing the files in Document directory. And after my work completed, delete the files from document directory as like below:
NSMutableDictionary * Dictionary = [NSMutableDictionary alloc]init];
// Next every file storing into this dictionary like below
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *baseDir = [paths objectAtIndex:0];
NSString *pathComp = [baseDir stringByAppendingPathComponent:[NSString stringWithFormat:#"IMG%d.PNG",presentCount];
fileURL = [NSURL fileURLWithPath:pathComp];
[Dictionary setObject:fileURL forKey:fileURL];
while ([[Dictionary allKeys]count]!=0) {
NSURL *deleteFileURL = [[Dictionary allKeys] lastObject];
NSLog(#"Path %#",deleteFileURL.path);
[[NSFileManager defaultManager] removeItemAtPath:deleteFileURL.path error:nil];
[Dictionary removeObjectForKey:deleteFileURL];
}
Here my problem is, after delete the files from document directory, memory is not reduced, still it's occupying as like files exist. Due to this issue, my is crashing. So please help me how to clear the memory.
Actually i am getting the files(Photos ) from the server and first placing in documents directory,and trying to save using photo library.Once i give input from dictionary to photo library, after completion handler, i am trying to delete the file.Its removed and photo saved, but memory is not reduced.
1、Remove the file after checking for the existence of a file on the path, and check the return value of removeItemAtPath: to determine if the deletion succeeded.
NSString *path = #"a/b";
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
// Check the success's value
}
I am currently using this code to copy my SQLite database, however it is currently only checking to see if the file exists... I want to change it to check if the file isn't exactly the same, for example I am worried if a database gets corrupt or doesn't copy all the way, the app will lose functionality and the only way to fix this would be to delete the App and redownload it.
So how can I compare if two files are exactly equal?
- (void) copyDatabaseIfNeeded {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
//NSLog(#"%d",success);
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database01.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
- (NSString *) getDBPath
{
//Search for standard documents using NSSearchPathForDirectoriesInDomains
//First Param = Searching the documents directory
//Second Param = Searching the Users directory and not the System
//Expand any tildes and identify home directories.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
//NSLog(#"dbpath : %#",documentsDir);
return [documentsDir stringByAppendingPathComponent:#"database01.sqlite"];
}
You can use contentsEqualAtPath:andPath: method of NSFileManager for this purpose.
Use your code something like this:
......
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database01.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
success = [fileManager contentsEqualAtPath:defaultDBPath andPath:dbPath]; //verify if file size and content matches
if(!success) {
//report error
}
}
.......
And it should do the trick for you.
Edit - Forget this answer - use the one by Ayan.
Start by comparing the file sizes. If the sizes are different you know the files are not the same. This is a simple and quick check.
If the sizes are the same then you need to compare the files, byte by byte. An inefficient way would be to load both files into NSData objects and see if they are equal. This only works if the files will always be small enough to fit in memory.
A better approach is to open both files as streams and read them in chunks. Compare each chunk (say 2k each) until two chunks are different or you get to the end.
Pulling my hair out trying to work this out. i want to read and write a list of numbers to a txt file within my project. however [string writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error] doesnt appear to write anything to the file. I can see there is the path string returns a file path so it seems to have found it, but just doesnt appear to write anything to the file.
+(void)WriteProductIdToWishList:(NSNumber*)productId {
for (NSString* s in [self GetProductsFromWishList]) {
if([s isEqualToString:[productId stringValue]]) {
//exists already
return;
}
}
NSString *string = [NSString stringWithFormat:#"%#:",productId]; // your string
NSString *path = [[NSBundle mainBundle] pathForResource:#"WishList" ofType:#"txt"];
NSError *error = nil;
[string writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", error.localizedFailureReason);
// path to your .txt file
// Open output file in append mode:
}
EDIT: path shows as /var/mobile/Applications/CFC1ECEC-2A3D-457D-8BDF-639B79B13429/newAR.app/WishList.txt so does exist. But reading it back with:
NSString *path = [[NSBundle mainBundle] pathForResource:#"WishList" ofType:#"txt"];
returns nothing but an empty string.
You're trying to write to a location that is inside your application bundle, which cannot be modified as the bundle is read-only. You need to find a location (in your application's sandbox) that is writeable, and then you'll get the behavior you expect when you call string:WriteToFile:.
Often an application will read a resource from the bundle the first time it's run, copy said file to a suitable location (try the documents folder or temporary folder), and then proceed to modify the file.
So, for example, something along these lines:
// Path for original file in bundle..
NSString *originalPath = [[NSBundle mainBundle] pathForResource:#"WishList" ofType:#"txt"];
NSURL *originalURL = [NSURL URLWithString:originalPath];
// Destination for file that is writeable
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL *documentsURL = [NSURL URLWithString:documentsDirectory];
NSString *fileNameComponent = [[originalPath pathComponents] lastObject];
NSURL *destinationURL = [documentsURL URLByAppendingPathComponent:fileNameComponent];
// Copy file to new location
NSError *anError;
[[NSFileManager defaultManager] copyItemAtURL:originalURL
toURL:destinationURL
error:&anError];
// Now you can write to the file....
NSString *string = [NSString stringWithFormat:#"%#:", yourString];
NSError *writeError = nil;
[string writeToFile:destinationURL atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", writeError.localizedFailureReason);
Moving forward (assuming you want to continue to modify the file over time), you'll need to evaluate if the file already exists in the user's document folder, making sure to only copy the file from the bundle when required (otherwise you'll overwrite your modified file with the original bundle copy every time).
To escape from all the hassle with writing to a file in a specific directory, use the NSUserDefaults class to store/retrieve a key-value pair. That way you'd still have hair when you're 64.
The code is copied below. I am using the documents directory because I know you can write outside of your apps sandbox.
I also compare the string I was using to determine the path to one created by the NSFileManager and they are the same. What do you all think?
- (NSString *)documentsDirectory
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
return [paths objectAtIndex:0];
}
- (void) whateverFunction{
NSString *memfileName = #"memmapfile.map";
NSString *filePath = [[self documentsDirectory] stringByAppendingPathComponent:memfileName];
NSLog(#"Here is the filePath: %#", filePath);
NSLog(#"Other version: %s", [[NSFileManager defaultManager] fileSystemRepresentationWithPath:filePath]);
int memFD = open([filePath cStringUsingEncoding:NSASCIIStringEncoding], O_RDWR);
NSLog(#"I am getting -1 for memFD: %d", memFD);
}
I'd guess your file doesn't exist yet, so of course you can't open it. You should add O_CREAT to your open flags so that it gets created if it doesn't exist:
int memFD = open([filePath cStringUsingEncoding:NSASCIIStringEncoding], O_RDWR|O_CREAT);
The problem is appearing on device not on simulator.
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Plist1.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSLog(#"documentsDirectory --- %#", documentsDirectory);
NSLog(#"path --- %#", path);
#try
{
if (![fileManager fileExistsAtPath:path])
{
[fileManager copyItemAtPath:documentsDirectory toPath:path error:&error];
}
}
#catch (NSException *exception)
{
NSLog(#" [exception description] -- %#", [exception description]);
}
#finally {
}
[dictEmot writeToFile:path atomically:YES];
// To verify
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSLog(#"[dict allKeys] My plist ----- %#", [dict allKeys]);
Above is the code which I have written to save two plist files in my documents directory. same method I use to save my second plist.
[self savePlist:plist1];
[self savePlist:plist2];
My problem is whenever I try to save second plist it creates hierarchy of folders inside documents directory and also not saves my plist2 file with it contents.
once it complets the 2nd method call, my app documents directory looks like below,
Documents
-> plist1
-> plist1
.
.
.
-> plist1
-> plist1
other files
I treid doing on main thread also but same result.
its not even printing exception.
What is my mistake ?
- Why its creating hierarchy ?
I don't know much about iOS but I think your problem is with stringByAppendingPathComponent:#"Plist1.plist" Check your documentation as I am supscious by the word Appending and even if you send new file name as you are hardcoding the value of the filename to Plist1.plist...
Still I am not sure as I have not done iOS coding for a long time now.