How can text files be written using Objective-C? - objective-c

In .NET, a file can be written to the file system using:
FileStream fs = File.Create(#"Filename");
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("Hello, World!");
// etc...
sw.Close();
fs.Close();
How would I achieve the same operation in Objective-C and Cocoa? I believe it involves the NSMutableData class, but I do not know how to implement it.

Tiny Mac Tutorials has a post on this.
The example code from that post is below:
// filetest.m
// Created by macateeny.blogspot.com Sept 2008.
// Copyleft (c) 2008. some rights reserved.
//
// Compile from the command line with:
// gcc filetest.m -Wall -o filetest -framework Foundation
//
#import <Foundation/Foundation.h>
// main entry point of our file test tool with the argument counter and vector
int main(int argc,char *argv[])
{
// allocate a memory pool for our NSString Objects
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// declare NSString Obj pointer and initialise it
NSString *str = #"Cooking with Objective-C\r\n";
// declare NSString filename and alloc string value
NSString *filenameStr = #"./filetest.txt";
// NSObject which contains all the error information
NSError *error;
// write contents and check went ok
if(![str writeToFile: filenameStr atomically: YES encoding:NSUTF8StringEncoding error:&error]) {
NSLog(#"We have a problem %#\r\n",[error localizedFailureReason]);
}
// unleash the allocated pool smithers
[pool release];
// The app is terminated
return 0;
}

Note that Objective C is a pure superset of standard C . Most of the usual posix library calls (in stdio, stdlib, etc.) are available and usable, as long as you don't try to use them to escape the app's sandbox (write to system directories, etc.)
So fopen() and fprintf() will also work perfectly well for writing ASCII or UTF8 text and data to files. You can use NSSearchPathForDirectoriesInDomains to find the appropriate directory names, and use various NSString convenience methods to convert NSStrings to UTF8.

See Apple's development docs - Cocoa concepts especially for this re Strings The Apple overview documents of the librairead all the concepts first it will give you a idea of what details you need

For the latest version of Cocoa on iOS or MacOS you can do this if you don't want to check for an error,
NSString *str = #"Wollah";
[str writeToFile:#"Wollah.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];

NSString *str = #"Wollah";
[str writeToFile:#"/Wollah.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
Although using an NSURL is recommended, and I always do that.

NSString has a writeToFile method.

Related

Initialize static NSString at class level

I have a NSString that should be constant in my class. I used the following code to accomplish this:
#interface DefinitionViewController ()
#end
static NSString *preamble;
#implementation DefinitionViewController {
}
+(void)initialize {
if (self == [DefinitionViewController class]) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"preamble" ofType:#"html"];
preamble = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding
error:nil];
}
}
It seems to work fine. I worry about using a file read inside an initialize. Is there a more appropriate means to accomplish the same goal (shared static string)? I could bury this inside my code, but it was much easier to maintain the somewhat large string as an external file.
Thanks for any advice.
"I worry about using a file read inside an initialize".
Don't (worry). The fact that it is, for example, a class method is utterly irrelevant. It is code. It runs and does its job. It is sound code, it runs coherently at a coherent time, and your app bundle is a real thing that really contains the resource. There's no problem here.
If you want to postpone creation of the string, and make assurance doubly sure that the string is not initialized twice, you could instead use a singleton pattern so that the string value is not generated until the first time it is explicitly requested:
+ (NSString*) preamble {
static NSString* preamble = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *path = [[NSBundle mainBundle] pathForResource:#"preamble" ofType:#"html"];
preamble = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
});
return preamble;
}
But there is no special need for this. (EDIT: But see, to the contrary, the comment below of #bbum, who Really Knows Stuff.)

Why my program can run in Xcode, but cannot running as a separate app?

My program loads some data from a file and then draws them.
The file-reading part is like this:
- (void)load_file
{
NSFileHandle *inFile = [NSFileHandle fileHandleForReadingAtPath:#"map_data"];
NSData *myData=[inFile readDataToEndOfFile];
NSString *myText=[[NSString alloc]initWithData:myData encoding:NSASCIIStringEncoding];
NSArray *values = [myText componentsSeparatedByString:#"\n"];
for (NSString *string in values) {
NSArray *lines=[string componentsSeparatedByString:#" "];
if ([lines count] != 2) break;
NSPoint point= NSMakePoint([lines[0] floatValue], [lines[1] floatValue]);
[points addObject:[NSValue valueWithPoint:point]];
}
[self setNeedsDisplay:YES];
}
When debugging, I put the data file in the directory of [NSBundle mainBundle], and the program works fine.
However, when I use achieve to take the app out, it never runs. I put the data file in the same path with the app, but it seems fail to load it.
Update
I tried to use c++, but still fails.
- (void)load_file
{
ifstream inf("map_data");
double x, y;
while (inf >> x >> y) [points addObject:[NSValue valueWithPoint:NSMakePoint(x, y)]];
inf.close();
}
I tried to change the build scheme to release and run, which is fine. But whenever I go directly into the finder of app and double click it, it does not work and seems nothing is loaded.
add the file to the project as a Resource (this will cause it to be copied into the app wrapper in the right spot)
use `[[NSBundle mainBundle] pathForResource:#"map_data" ofType:nil];
That should give you the path to the file. The file should not be manually copied, it should not be next to the app wrapper, nor should you [conjecture] ever try changing or replacing the file once it is in your app wrapper.
The reason why it seems to work sometimes is mere coincidence. You are passing a partial path to NSFileHandle and it happens that the current working directory of your app sometimes points to the right spot such that the data file is available.
I'm not sure how relative paths are handled by NSFileHandle, but usually you set up paths using the NSBundle class.
NSString *path = [[NSBundle mainBundle] pathForResource:#"myfile" ofType:#"ext"];
You can also simply initialize an NSString from the contents of a file, you don't need to first read it into an NSData using NSFileHandle.
NSString *text = [[NSString alloc] initWithContentsOfFile:path
encoding:NSASCIIStringEncoding error:nil];
(Use the error parameter, if you want proper error handling)

NSString WriteToFile not stay permanent?

I am trying to save text stored in an NSString variable in a text file that is stored with the main bundle of my project.
So far I have had no success and tried a lot of different methods.
Why doesn't this stay permanent?
NSString *pathToFile = [[NSString alloc]init];
pathToFile = [[NSBundle mainBundle] pathForResource:#"ListOfSavedImages" ofType:#"txt"];
NSLog(#"%#",pathToFile);
NSString *stringToWriteToFile = [[NSString alloc]init];
stringToWriteToFile=#"Adam";
NSLog(#"%#",stringToWriteToFile);
[stringToWriteToFile writeToFile:pathToFile atomically:YES encoding:NSUTF8StringEncoding error:NULL];
NSLog(#"called!");
NSString *contentsOfFile1 = [NSString stringWithContentsOfFile:pathToFile encoding:NSUTF8StringEncoding error:NULL];
NSLog(#"%#",contentsOfFile1);
The actual file doesn't change although the NSLog at the end of this code segment outputs "Adam" but I am also nslogging the contents of the file when the view loads and it always reverts back to the original text(it never actually changes). What am I doing wrong?
I am using Xcode 4.3, ARC, and storyboards.
As you are instantiating your variables locally, they will leak away when you hit the end of the block }.
Try using IVars declared as properties of the particular view controller, synthesized in the .m file.
Look at the C139p at Stanford Course on ITunes, preferably the earlier series given before ARC as this fully explains the concept of data persistence.

Opening a txt file and outputting contents in objective-c (but not for OSX or iOS)

Just to give context to my problem, I often have to run search and replace on CSV files. I would like to start doing this by coding my needs in Objective-C and then run the executable to get the job done.
I currently have this chunk of code to open a file and stick it's contents into a string. I then compile it in terminal and then run it.
Here is the code of the entire program:
#import <Foundation/Foundation.h>
int main (int argc, const char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog (#"Running....");
NSString* filePath = #"/Users/xxxxxx/Desktop/test_level2.txt";
NSString* fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSLog(#"file contents --->%#", fileContents);
[pool drain];
return 0;
}
The weird thing about this is that it prints only some of the contents of the file. Out of 20 lines, it prints the first and the last and some random parts from the middle.
Any idea of how I can solve this? Any suggests of how I can get the entire contents of the file into an NSString?
You sure there's not some carriage returns rather than new lines in there?
Does it do the same thing when you do cat /Users/xxxxxx/Desktop/test_level2.txt?

File Handling in Objective C

Is there anyway to do Files Handling in Objective-C? I am just trying to do simple read and write and can use 'c' but i am force to use Objective-C classes for that :#. I am looking into NSInputStream, but its going over my head. Is there any tutorial which explains how to use NSInputStream?
I had trouble with basic file i/o when I first hit it in Obj-C as well. I ended up using NSFileHandle to get C style access to my file. Here's a basic example:
// note: myFilename is an NSString containing the full path to the file
// create the file
NSFileManager *fManager = [[NSFileManager alloc] init];
if ([fManager createFileAtPath:myFilename contents:nil attributes:nil] != YES) {
NSLog(#"Failed to create file: %#", myFilename);
}
[fManager release]; fManager = nil;
// open the file for updating
NSFileHandle *myFile = [NSFileHandle fileHandleForUpdatingAtPath:myFilename];
if (myFile == nil) {
NSLog(#"Failed to open file for updating: %#", myFilename);
}
// truncate the file so it is guaranteed to be empty
[myFile truncateFileAtOffset:0];
// note: rawData is an NSData object
// write data to a file
[myFile writeData:rawData];
// close the file handle
[myFile closeFile]; myFile = nil;
If all you need to do is really simple I/O, you can just tell an object to initialize itself from, or write itself to, a filesystem path or URL. This works with several Foundation classes, including NSString, NSData, NSArray, and NSDictionary among others.
Try starting out by looking at the following two NSString methods:
- initWithContentsOfFile:encoding:error:
- writeToFile:atomically:encoding:error:
I find apple's guides short and to the point.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html