Determine folder Size - objective-c

With this code I determine the file size if the checkbox is NSOnState, but with a folder value is always 0. The directory is correct.
Can you help me?
unsigned long long resultsize=0;
if(imagehistoryS.state == NSOnState) {
NSString *path = [NSString stringWithFormat:#"Users/Giovanni/Desktop/test", [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
NSNumber *fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] objectForKey:NSFileSize];
resultsize += [fileSize doubleValue];
}
[result setStringValue:[NSString stringWithFormat:#"Total size items selected: %f", resultsize]];

You're passing in a string, and yet specifying the NSUserDomainMask. I've tried this and it works.
NSUInteger resultSize = 0;
NSFileManager *fm = [[NSFileManager alloc] init];
NSURL *LibraryURL = [[fm URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *previewsURL = [LibraryURL URLByAppendingPathComponent:#"/Caches/com.apple.Safari/Webpage Previews"];
resultSize = [[[fm attributesOfItemAtPath:[previewsURL path] error:nil] objectForKey:NSFileSize] unsignedIntegerValue];
NSLog(#"Size: %lu", resultSize);
This is for an ARC environment.
Note, I'm using NSURLs instead of NSString filepaths as much as possible. Also, you don't need to hardcode the user's name in the search path.
Updated to show the specific folder as requested in the comments

In you stringWithFormat you are missing the format specifier %#.

Related

Objective-C Split a String and get last item

I have a string like so:
NSString *path = #"\\fake\aaa\bbb\ccc\ddd\eee.pdf";
and I split the string into an array like so:
NSArray *array = [path componentsSeparatedByString:#"\"];
Now there are two things I need here.
I need a string with everything except eee.pdf
I need the last item in the array as a string (eee.pdf)
How would I do this?
Just for fun, there is a little-known way to get an NSURL with its benefit from a windows file path
NSString *path = #"\\\\fake\\aaa\\bbb\\ccc\\ddd\\eee.pdf";
NSURL *url = CFBridgingRelease(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)path, kCFURLWindowsPathStyle, false));
NSString *fileName = url.lastPathComponent;
NSString *parentDirectory = url.URLByDeletingLastPathComponent.path;
Finally you have to convert parentDirectory back to windows path style (backslashes).
But if you mean POSIX paths used in OS X, it's much easier
NSString *path = #"/fake/aaa/bbb/ccc/ddd/eee.pdf";
NSURL *url = [NSURL fileURLWithPath:path];
NSString *fileName = url.lastPathComponent;
NSString *parentDirectory = url.URLByDeletingLastPathComponent.path;
I think you're trying to get the filepath and filename from a full path. There are better ways of doing that. But since you simply asked for the question, here's my answer. Please note that this is not the best approach. In addition, you have to escape the backslashes by using a preceding backslash.
NSString *path = #"\\fake\\aaa\\bbb\\ccc\\ddd\\eee.pdf";
NSArray *array = [path componentsSeparatedByString:#"\\"];
NSMutableArray *removedArray = [[NSMutableArray alloc] init];
for(int i=0; i< array.count -1; i++){
[removedArray addObject:[array objectAtIndex:i]];
}
NSString *joinedString =[removedArray componentsJoinedByString:#"\\"];
NSString *fileName = [array lastObject];
NSLog(#"Path: %#", joinedString);
NSLog(#"Filename: %#", fileName);
For the last element use the lastObject property of the NSArray.
For a string without the last element use subarrayWithRange: using array.count-1 for the NSRange length.
Then join the remaining array with componentsJoinedByString:.
NSString *fileName = [array lastObject];
NSArray *newArray = [array subarrayWithRange:NSMakeRange(0, array.count-1)];
NSString *directoryPath = [newArray componentsJoinedByString:#"\\"];

Error writing to long value to file Objective-C

I'm trying to create 9 text files on my Desktop which are named by variable i in the for loop. Inside each text file I want to write a long value determined by my bigInt function. The long value must then be written in the file 1000 times before moving on to the next text file. But I keep getting the error: Incompatible pointer types sending 'NSString*' to parameter of type 'NSData*'
My Function:
long bigInt(int i){
long big = 99*(i*99);
long evenBigger = big*(big*(big*big));
return evenBigger;
}
My main method:
long use;
int x = 0;
for (int i = 1; i<10; i++) {
while (x < 1000) {
use = bigInt(i);
//[NSString stringWithFormat:#"%ld", use];
//NSString *content = #"Text to write to file";
NSString *path = [NSString stringWithFormat: # "/Users/ou_snaaksie/Desktop/%i.txt", i];
//NSData *fileContents = [use dataUsingEncoding:NSUTF8StringEncoding];
[[NSFileManager defaultManager] createFileAtPath:path contents:[NSString stringWithFormat:#"%ld", use] attributes:nil];
x++;
}
}
I think you need to pass NSData instead of NSString object to contents in createFileAtPath:contents:attributes: method or you can do something like below:
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
}
[[string dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES];
You are passing a string as contents when it requires NSData. You have to convert the string to NSData. Try this in the body of your while loop:
use = bigInt(i);
NSString* str = [NSString stringWithFormat:#"%ld", use];
NSData* data_contents = [str dataUsingEncoding:NSUTF8StringEncoding];
NSString *path = [NSString stringWithFormat: # "/tmp/%i.txt", i];
[data_contents writeToFile:path atomically:YES];
x++;

Show contents of two merged directory listings

I would like to merge the two directories listings (already done and works they show up in NSTableView), but also display the contents of the files in an NSScrollview, now the problem lies in iterating through the list, and I couldn't figure out how I would come about that problem, I tried different techniques.
For now I get: "-[NSTextView replaceCharactersInRange:withString:]: nil NSString given.", probably because the iteration code is incorrect...
NSInteger row = [logsTableView selectedRow];
NSString *path1 = [NSHomeDirectory() stringByAppendingPathComponent:#"Library/Logs/"];
NSString *path2 = #"/Library/Logs/";
NSArray *directoryList1 = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path1 error:nil]
pathsMatchingExtensions:[NSArray arrayWithObjects:#"log", nil]];
NSArray *directoryList2 = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path2 error:nil]
pathsMatchingExtensions:[NSArray arrayWithObjects:#"log", nil]];
NSMutableArray *directoryList = [NSMutableArray array];
[directoryList addObjectsFromArray:directoryList1];
[directoryList addObjectsFromArray:directoryList2];
for (NSUInteger i = 0; i < directoryList.count; i++)
{
if (row == i)
{
for (NSUInteger i = 0; i < directoryList1.count; i++)
{
NSString *filePath = [NSHomeDirectory() stringByAppendingFormat:#"Library/Logs/%#", [directoryList objectAtIndex:i]];
NSString *content = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:NULL];
[logsScrollViewTextView setString:content];
}
for (NSUInteger i = directoryList.count - directoryList1.count; i < directoryList.count; i++)
{
NSString *filePath = #[#"/Library/Logs/%#", [directoryList objectAtIndex:i]];
NSString *content = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:NULL];
[logsScrollViewTextView setString:content];
}
}
}
You don't need to iterate. All you need to do is to check which array the file name came from.
Assuming you aren't sorting the list, this is if (row >= directoryList1.count). This check tells you which list it came from so you can set the prefix.
If you are sorting and the names are unique you could use [directoryList1 containsObject:...).

Objective-C - Works with strings, find a substring with NSRange

I'm working with the strings and i have a little problem that i'm not understanding. In fact, i have a string like this: "ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=168BA548-9C81-4B08-B69C-B775E5DD9341&ext=JPG" and i need to find the string between "URLs:" and "?id=" . For doing this, i'm trying to create a new string using the NSRange. In this mode i give the first index and the last index that i need, but it seems not working.
Here there is my code:
NSString *description = [asset description];
NSRange first = [description rangeOfString:#"URLs:"];
NSRange second = [description rangeOfString:#"?id="];
NSString *path = [description substringWithRange: NSMakeRange(first.location, second.location)];
It return to me this kind of string: "URLs:assets-library://asset/asset.JPG?id=168BA548-9C81-4B08-B69C-B775E5DD9341&ext=JPG". Is it correct? I'm expecting to obtain "assets-library://asset/asset.JPG" string.
Where i'm doing wrong? Is there a better way to do this?
I have followed this url for help: http://www.techotopia.com/index.php/Working_with_String_Objects_in_Objective-C
Thanks
Try this range:
NSMakeRange(first.location + first.length, second.location - (first.location + first.length))
Don't parse the ALAsset description string! If the description ever changes your code breaks. Use the methods ALAsset and NSURL provide you. First, get the dictionary of URLs (mapped by asset type) through the valueForProperty: method. Then, for each URL, get the absoluteString and remove the query string from it. I got the string you were looking for by placing the following code in the application:didFinishLaunchingWithOptions: method from the single-view iPhone app template.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
NSDictionary *URLDictionary = [asset valueForProperty:ALAssetPropertyURLs];
for (NSURL *URL in [URLDictionary allValues]) {
NSString *URLString = [URL absoluteString];
NSString *query = [URL query];
if ([query length] > 0) {
NSString *toRemove = [NSString stringWithFormat:#"?%#",query];
URLString = [URLString stringByReplacingOccurrencesOfString:toRemove withString:#""];
NSLog(#"URLString = %#", URLString);
}
}
}];
} failureBlock:^(NSError *error) {
}];
NSRange first = [description rangeOfString:#"URLs:"];
gives you the position of the U, so you need to take first.location+5 to get the start position of assets-library.
NSRangeMake(loc,len) takes a starting location loc and a length, so you need to use second.location-first.location-5 to get the length you are looking for.
Adding it all up, replace the last line with:
NSRange r = NSMakeRange(first.location+5, second.location-first.location-5);
NSString *path = [description substringWithRange:r];

NSString.length gives EXC_BAD_ACCESS

I have the following code:
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
NSString *temp;
for (int i = 0; i < [array count]; i++)
{
temp = [array objectAtIndex:i];
NSLog(#"temp length = %#", [temp length]);
}
I get an EXC_BAD_ACCESS error at the NSLog line. I assume it's erring out at the [temp length] bit. The weird thing is, I can do other methods of NSString on temp and they work fine, like [temp characterAtIndex:0].
I've also tried doing [[array objectAtIndex:i] retain];, but that doesn't seem to help.
Does anyone know why I'm getting this error?
EDIT: Turns out it was crashing at the NSLog because it was %# instead of %lu. The real problem was with other code that I had omitted from this post. After playing around with it some more, I got it working.
From my understanding, the "%#" placeholder is for object pointers, "length" returns "NSUInteger" which is not a pointer. Try "%lu" instead of "%#".
This (slightly cleaned up) version works for me:
NSError *error = nil;
NSString *path = [#"~/Desktop" stringByExpandingTildeInPath];
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:
path error:&error];
if (error) NSLog(#"%#", error);
for (NSString *path in array) {
NSLog(#"Path length = %lu", path.length);
}
As thg435 mentioned, "%#" is for object pointers, so if you pass it an arbitrary number it will throw a memory access error.