Trouble accessing a .txt file. - objective-c

I have the following method that is meant to get all the words contained in text file and add them to an array. I think the problem is where my .txt file is located. I am adding it into the project explorer right next to the classes. I have read elsewhere that it is meant to go in your Resource folder, however I think newer versions of XCode no longer creates a resource folder for you. Regardless here is my method:
-(void) getWords
{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"WordList" ofType:#"txt"];
NSString *wordFile = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSArray* words = [wordFile componentsSeparatedByString:#"\n"];
NSLog(#"Found %lu words", (unsigned long)[words count]);
}
Could someone help me get this method to find my file? Where can I put the .txt file? Thanks.

Related

how to write to a file if I have path xcode

I'm trying to make a plugin for xcode where I want to write something to the h file from the m file. I can dynamically get the filepath from the class I'm currently writing code in, and by changing the .m to .h I'll have the filepath for the h file.
My question is, how do I write something to an .h file from xcode when I have the path?
NSString *path = #"your/path/tp/.h/file";
NSData *data = [NSData dataWithContentsOfFile:path];
//Get the contents of the file into the mutable string
NSMutableString *contents = [[NSMutableString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding];
//Make changes to your mutable string
[contents appendString:#"abc"];
//Write it back to the file
[contents writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
It´s not possible to do what you are asking. You can write only in files from your Documents Directory.
I don´t understand why do you need to write in a .h file for to change it. Maybe you could create subclasses from the same Class and you use one or other depending of your requirements

Parsing of m3u files in Objective-C for iPhone from file system or URL

The example below should take a link from m3u playlist and add it to anArray. (So I will get the NSArray(NSMutableArray) with certain links in it)
NSString *fileContents = [NSString stringWithContentsOfFile:#"myfile.m3u" encoding:NSUTF8StringEncoding error:NULL];
NSArray *lines = [fileContents componentsSeparatedByString:#"\n"];
NSLog (#"%#",lines);
All the time I had (null) in NSLog Message.
All the time when I try NSLog or if/else statement to check is there is link in array it gives me the null object in it.
After that I thought the problem was in m3u type and I've tried to change type in txt and read. (For those who don't know, M3U is just the text in UTF-8 encoding and the changing type should give the result)
Then I've tried the .txt files but it doesn't work too. So there is the code of it.
//Check if there is my file
NSString *addPath = [[NSBundle mainBundle] pathForResource:#"somefile" ofType:#"m3u" ];
if ([fileMgr fileExistsAtPath:addPath] ) {
NSLog(#"Yes.We see the file");
}
else {
NSLog(#"Nope there is no file");
}
//Rename
NSString *path1 = addPath;
NSString *theNewFilename = [path1 stringByReplacingOccurrencesOfString:#"m3u" withString:#"txt"];
NSLog(#"Renamed file adress is %#", theNewFilename);
//Check if there is our renamed file(file manager was allocated before)
NSString *addPath1 = [[NSBundle mainBundle] pathForResource:#"somefile" ofType:#"txt" ];
if ([fileMgr fileExistsAtPath:addPath1] ) {
NSLog(#"Yes we had the renamed file");
}
else {
NSLog(#"No we don't");
}
Checking is there is m3u file worked fine. I had Addres to Renamed file too. But when it was checking is there is renamed file, there was no file (null in NSLog).
After all that stuff, and without any hope to reach my destination I've tried to read txt file line by line separated by /n with 5 links in it.
NSString *fileContents1 = [NSString stringWithContentsOfFile:#"myfile.txt" encoding:NSUTF8StringEncoding error:NULL];
NSArray *lines1 = [fileContents1 componentsSeparatedByString:#"\n"];
NSLog (#"%#",fileContents1);
NSLog (#"%#",lines1);
Both Messages were NULL
One more thing all this stuff I tried to make in -(IBAction)fileRead { } linked to button
(Yes I've presed button every time to check my NSLog)Program was checked in iPhone Simulator. Will be glad if someone say what is the trouble. Also if there is easier way to make this with url. (Tried Couple times with NSUrl and had Nothing but null )
Just because you've changed the path doesn't mean that you've renamed/moved/copied an item, path is just a string. Use NSFileManager methods like
– moveItemAtURL:toURL:error: or
– moveItemAtPath:toPath:error:.
Also, NSString doesn't care about extension, so it's completely safe to read your m3u file to NSString, no need to rename it.
NSString *addPath = [[NSBundle mainBundle] pathForResource:#"somefile" ofType:#"m3u" ];
if ([fileMgr fileExistsAtPath:addPath] ) {
NSLog(#"Yes.We see the file");
NSString *fileContents1 = [NSString stringWithContentsOfFile:addPath encoding:NSUTF8StringEncoding error:NULL];
NSArray *lines1 = [fileContents1 componentsSeparatedByString:#"\n"];
NSLog (#"%#",fileContents1);
NSLog (#"%#",lines1);
}
else {
NSLog(#"Nope there is no file");
}

Adding text file to Xcode project and using it in app

I have a .txt file (in plain text format) and I would like to integrate this into a iOS app I am starting to write. The info in the text file must be searchable by the app. Is there a way to do this? If so, what would be best way to do so? Or would I need to add this text file into ViewController.m in code instead?
You will need to add the txt file to your project and then read it into memory. Here is one way to read the entire contents into memory at once:
NSString *path = [[NSBundle mainBundle] pathForResource:#"yourTextFile"
ofType:#"txt"];
NSError *error = nil;
NSString *data = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:&error];
if (error) {
// handle the error condition
} else {
// continue your processing
}

Write to file not working

I'm trying to combine images in my app into one file and write it to disk.
NSMutableArray *array = [NSMutableArray arrayWithObjects:
[NSData dataWithContentsOfFile:#"0.png"],
[NSData dataWithContentsOfFile:#"1.png"],
[NSData dataWithContentsOfFile:#"2.png"],
nil];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSError *error = nil;
NSString *path=#"/Users/myusername/Desktop/_stuff.dat";
[data writeToFile:path options:NSDataWritingAtomic error:&error];
or
NSArray *array = [NSArray arrayWithObjects:
[NSImage imageNamed:#"0"],
[NSImage imageNamed:#"1"],
[NSImage imageNamed:#"2"],
nil];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSError *error = nil;
NSString *path=#"/Users/myusername/Desktop/_stuff.dat";
[data writeToFile:path options:NSDataWritingAtomic error:&error];
But both produce a file that is 4KB (empty). If I NSLog the error it is (null). Am I making the data the wrong way?
Edit: If I open the resulting file with a text editor, it looks like this:
I wrote a quick example:
Missing: memory management / error handling / proper file handling
// Archive
NSMutableArray *array = [[NSMutableArray alloc] init];
NSString * input = #"/Users/Anne/Desktop/1.png";
[array addObject:[NSData dataWithContentsOfFile:input]];
[array addObject:[NSData dataWithContentsOfFile:input]];
[array addObject:[NSData dataWithContentsOfFile:input]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSString *path = #"/Users/Anne/Desktop/archive.dat";
[data writeToFile:path options:NSDataWritingAtomic error:nil];
// Unarchive
NSMutableArray *archive = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSData * firstObject = [archive objectAtIndex:0];
NSString * output = #"/Users/Anne/Desktop/2.png";
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:output];
[firstObject writeToURL:fileURL atomically:YES];
You can also add NSImages to the NSMutableArray:
NSString * input = #"/Users/Anne/Desktop/1.png";
NSImage *image = [[NSImage alloc] initWithContentsOfFile: input];
[array addObject:image];
But that will significantly increase the file size.
Response to the following comment:
So if I only need to access an image at runtime (in the archive), is there a way to access that image at an index without unarchiving the whole thing? Seems like unnecessary overhead to me.
I assume you're still struggling with this problem?
Hiding (or encrypting) app resources?
Like i mentioned earlier, combining all files into one big file does the trick.
Just make sure you remember the file-length of each file and file-order.
Then you can extract any specific file you like without reading the whole file.
This might be a more sufficient way if you only need to extract one file at the time.
Quick 'dirty' sample:
// Two sample files
NSData *fileOne = [NSData dataWithContentsOfFile:#"/Users/Anne/Desktop/1.png"];
NSData *fileTwo = [NSData dataWithContentsOfFile:#"/Users/Anne/Desktop/2.png"];
// Get file length
int fileOneLength = [fileOne length];
int fileTwoLength = [fileTwo length];
// Combine files into one container
NSMutableData * container = [[NSMutableData alloc] init];
[container appendData:fileOne];
[container appendData:fileTwo];
// Write container to disk
[container writeToFile:#"/Users/Anne/Desktop/container.data" atomically:YES];
// Read data and extract sample files again
NSData *containerFile = [NSData dataWithContentsOfFile:#"/Users/Anne/Desktop/container.data"];
NSData *containerFileOne =[containerFile subdataWithRange:NSMakeRange(0, fileOneLength)];
NSData *containerFileTwo =[containerFile subdataWithRange:NSMakeRange(fileOneLength, fileTwoLength)];
// Write extracted files to disk (will be exactly the same)
[containerFileOne writeToFile:#"/Users/Anne/Desktop/1_extracted.png" atomically:YES];
[containerFileTwo writeToFile:#"/Users/Anne/Desktop/2_extracted.png" atomically:YES];
// Only extract one file from the container
NSString * containerPath = #"/Users/Anne/Desktop/container.data";
NSData * oneFileOnly = [[NSFileHandle fileHandleForReadingAtPath:containerPath] readDataOfLength:fileOneLength];
// Write result to disk
[oneFileOnly writeToFile:#"/Users/Anne/Desktop/1_one_file.png" atomically:YES];
Tip:
You can also save the 'index' inside the container file.
For example: The first 500 bytes contain the required information.
When you need a specific file: Read the index, get the file position and extract it.
You are archiving a NSMutable array of NSImage. This two classes conform to the NSCoding protocol required by NSKeyedArchiver, so I don't see where would be your problem.
So, here are many ideas to test.
First, are you sure that the data you think you have are valid? In your first code snippet, you write [NSData dataWithContentsOfFile:#"0.png"]. This method expects an absolute file path.
Assuming the problem is not in your code, just in your question, let's continue:
Do you have something different than nil in the variable data after your archiving? Ie, after the assignement to data, can you add this code. If the assertion fail, you will get an exception at runtime:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSAssert(nil != data, #"My object data is nil after archiving");
If the problem was not here, what is the return of the line [data writeToFile:path options:NSDataWritingAtomic error:&error];
(Not the variable error, but the return value of the call to the method - writeToFile: options: error:)
What happens if you simplify your code and just do this:
result = [NSKeyedArchiver archiveRootObject:data
toFile:archivePath];
If everything was ok, have you tried to unarchive your file with NSKeyedUnarchiver?
The problem is that [NSData dataWithContentsOfFile:#"0.png"] looks for the file "0.png" in the current directory, but what the application thinks of as the current directory is probably not the place you're expecting. For graphical apps, you should always either use an absolute path or a path relative to some place that you can get the absolute path of (e.g. your app bundle, the application support directory, some user-selected location).
For command-line tools, using the current directory is more common. But I doubt that's the case here.
Another thing I noticed on Mavericks and up is that the folders in the path must be in existence. Meaning you must create the folder structure prior to saving into that folder. If you try to write to a folder on the desktop or elsewhere, even with sandboxing off, it will fail if the folder does not exist. I know this has been answered already, but I found that my issue continued regardless, but once I make sure that the folder structure was in place, I could do my writing to that folder.
On a side note: I'm sure that you could do this from NSFileManager, and I'll be doing that myself once I finalize my app structure, but hope this helps someone else lost in the sauce.

Saving a string into file in Objective-C (iPhone)

I seem to have stumbled over a problem regarding saving an xml file from a string (this is done on the iPhone)
The file itself exists and included in the project (hence within the workspace), and all indications I get from the code snippet which follows passes without any errors on the emulator and fail on the iPhone (error 513), but in either case the file is not saved!
{
Hits = config->Hits;
NSString* filenameStr = [m_FileName stringByAppendingFormat: #".xml" ];
NSString* pData = [self getDataString]; // write xml format - checked out ok
NSError *error;
/* option 2 - does not work as well
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *xmlURL = [NSURL fileURLWithPath:[mainBundle pathForResource: m_FileName ofType: #"xml"]];
if(![pData writeToURL: xmlURL atomically: true encoding:NSUTF8StringEncoding error:&error])
{
NSLog(#"Houston - we have a problem %s#\n",[error localizedFailureReason]);
return false;
}
*/
if(![pData writeToFile: filenameStr atomically: FALSE encoding:NSUTF8StringEncoding error:&error])
{
NSLog(#"Houston - we have a problem %s#\n",[error localizedFailureReason]);
return false;
}
return true;
}
Any help would be appreciated,
-A
You should not write to files included in the application package. On a real iPhone, you may be prevented from doing this because these files are digitally signed.
Even if you can modify a packaged file, it is not a good place to store data. Re-installing the application from an App Store upgrade or an Xcode build will overwrite the file with the original.
Instead, store your XML into the Documents directory. You can get the path like this:
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* leafname = [m_FileName stringByAppendingFormat: #".xml" ];
NSString* filenameStr = [documentsDirectory
stringByAppendingPathComponent:leafname];
If your file needs some initial state that you don't want to generate in your code, have your app check that it is present in the documents directory the first time it is needed and, if it is missing, copy it from the template in the package.
An alternative to storing structured data is to use user defaults. For example:
[[NSUserDefaults standardUserDefaults] setObject:foo forKey:FOO_KEY];