WriteData causes sigabrt error - objective-c

I want to read a file (hello.in) and to write it to another file line by line.
I write the below method and when I run it I get sigabrt error.
I would love to get answer.
-(void) saveAsLineLine: (NSString*) fileName
{
NSString *filePath;
filePath = [NSString stringWithFormat:#"%#%#", pathdir, #"hello.in"];
// reading the file
NSString *entireFileInString = [NSString stringWithContentsOfFile:filePath encoding:(NSUTF8StringEncoding) error:nil];
// each line, adjust character for line endings
NSArray *lines = [entireFileInString componentsSeparatedByString:#"\n"];
filePath = [NSString stringWithFormat:#"%#%#", pathdir, fileName];
// create a file
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
// open the file for writeing
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:filePath];
// write line by line
for (NSData *line in lines)
{
NSLog (#"line: %#\n", line);
[fh seekToEndOfFile];
[fh writeData: line]; // THE BUG IS HERE !!!!!!!!
// #try {
// [fh writeData: line];
//
// }
// #catch (NSException *exception) {
// NSLog(#"%#",[exception description]);
// }
}
[fh closeFile];
}

The NSArray lines holds instances of NSString, not NSData, right?
If you want to write data to file...
[lines enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSData *lineData = [obj dataUsingEncoding:NSUTF8StringEncoding];
[fh seekToEndOfFile];
[fh writeData:lineData];
}];

Related

Objective c / How do I call a user-implemented static function into the nsstring class?

+ (NSString *)dictionaryToJson:(NSDictionary *)dic
{
NSString *result = #"";
NSError *err;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&err];
if(! jsonData) {
NSLog(#"Error: %#", err);
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
result = jsonString;
}
return result;
}
The functions that we define here are
[body appendData:[[NSString dictionaryToJson:jsonBody] dataUsingEncoding:NSUTF8StringEncoding]];
I don't think you understood the function call from objc yet. Please help me.
here you'd typically extend the class using a category. See e.g. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html
// Header file
// Something like NSString+JSONAdditions.h
#interface NSString (JSONAdditions)
+ (NSString *)dictionaryToJson:(NSDictionary *)dic;
#end
// Implementation file
// Something like NSString+JSONAdditions.m
#implementation NSString (JSONAdditions)
+ (NSString *)dictionaryToJson:(NSDictionary *)dic
{
NSString *result = #"";
NSError *err;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&err];
if(! jsonData) {
NSLog(#"Error: %#", err);
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
result = jsonString;
}
return result;
}
#end
Now you can use the code as in the snippet you provided. FWIW in Xcode do this using
File -> New -> File ... -> Objective-C file

Corrupted files downloaded from Amazon S3 using AFAmazonS3Client

I created an app that download a plist file from Amazon S3. I was using AFAmazonS3Client a client based in AFNetworking framework.
-(void) getFile:(NSString *)fileName{
self.s3Manager = [[AFAmazonS3Manager alloc] initWithAccessKeyID:#"..." secret:#"..."];
self.s3Manager.requestSerializer.region = AFAmazonS3SAEast1Region;
self.s3Manager.requestSerializer.bucket = #"verba";
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
documentsPath = [documentsPath stringByAppendingPathComponent:fileName];
NSOutputStream *stream = [[NSOutputStream alloc] initToFileAtPath:documentsPath append:NO];
[self.s3Manager getObjectWithPath:#""
outputStream:stream
progress:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"%f%% Downloaded", (totalBytesRead / (totalBytesExpectedToRead * 1.0f) * 100));
} success:^(id responseObject) {
NSLog(#"Download Complete");
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Then I checked if the plist file was in document folder. And it was. So I tried to open plist file and the result was nil:
-(NSString*) loadListName:(NSString*)fileName{
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* filePath = [documentsPath stringByAppendingPathComponent:fileName];
NSDictionary *temp;
if ([[NSFileManager defaultManager] fileExistsAtPath: filePath]){
temp = [NSDictionary dictionaryWithContentsOfFile:filePath];
} else {
NSLog(#"File not found.");
}
NSString *listName = [temp objectForKey:#"name"];
return listName;
}
So I tried to add plist file manually. I downloaded and copied it to the documents folder and then dictionaryWithContentsOfFile could open the file. So I suppose that plist file was corrupted when I download the file using AFAmazonS3Client.
What I am doing wrong ?
Update 1
I realize that every single file that I downloaded from S3 are corrupted. I don't know if I handle the NSOutputStream in the right way or maybe another stuff.
For some reason getObjectWithPath method from AFAmazonS3Manager is not working properly.
So I rewrite my method using AFHTTPRequestOperation directly from AFNetworking
- (void)downloadFile:(NSString *)fileName block:(void (^)(NSError *error))block {
NSString *urlString = #"https://[bucket].[server area].amazonaws.com/";
urlString = [urlString stringByAppendingPathComponent:fileName];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSSet *set = operation.responseSerializer.acceptableContentTypes;
if ([[fileName pathExtension] isEqualToString:#"m4a"]) {
NSLog(#"%# set as audio/mp4", fileName);
operation.responseSerializer.acceptableContentTypes = [set setByAddingObject:#"audio/mp4"];
} else if ([[fileName pathExtension] isEqualToString:#"png"]) {
NSLog(#"%# set as image/png", fileName);
operation.responseSerializer.acceptableContentTypes = [set setByAddingObject:#"image/png"];
} else if ([[fileName pathExtension] isEqualToString:#"plist"]) {
NSLog(#"%# set as application/x-plist", fileName);
operation.responseSerializer.acceptableContentTypes = [set setByAddingObject:#"application/x-plist"];
}
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fullPath = [documentsPath stringByAppendingPathComponent:[url lastPathComponent]];
[operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:fullPath append:NO]];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"bytesRead: %lu, totalBytesRead: %lld, totalBytesExpectedToRead: %lld", (unsigned long)bytesRead, totalBytesRead, totalBytesExpectedToRead);
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (block) {
block(nil);
}
NSLog(#"RES: %#", [[[operation response] allHeaderFields] description]);
NSError *error;
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:&error];
if (error) {
NSLog(#"ERR: %#", [error description]);
} else {
NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
long long fileSize = [fileSizeNumber longLongValue];
NSLog(#"%lld", fileSize);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (block) {
block(error);
}
NSLog(#"ERR: %#", [error description]);
}];
[operation start];
}
Be carefull cause in last versión of Xcode, every time you restart your app in simulator, the documents folder is deleted

Create csv file from array of data in iOS

I want to write data from sql file to csv file. I have collected all data from sql file in an array and using for loop i am appending and writing data to .csv file. but it seems that it shows data in one line only it does not go to new line to create new row.
I have used this for reference.
This is my code :
-(NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"myfile.csv"];
}
- (IBAction)saveAsFileAction:(id)sender {
if (![[NSFileManager defaultManager] fileExistsAtPath:[self dataFilePath]]) {
[[NSFileManager defaultManager] createFileAtPath: [self dataFilePath] contents:nil attributes:nil];
NSLog(#"Route creato");
}
NSString *writeString;
for (int i=0; i<[dataArray count]; i++) {
writeString = [NSString stringWithFormat:#"%#, %#, %#, %#, %0.2f,",[[dataArray objectAtIndex:i]dates],[[dataArray objectAtIndex:i] time],[[dataArray objectAtIndex:i] category],[[dataArray objectAtIndex:i]place],[[dataArray objectAtIndex:i] amount]];
NSLog(#"writeString :%#",writeString);
NSFileHandle *handle;
handle = [NSFileHandle fileHandleForWritingAtPath: [self dataFilePath] ];
//say to handle where's the file fo write
[handle truncateFileAtOffset:[handle seekToEndOfFile]];
//position handle cursor to the end of file
[handle writeData:[writeString dataUsingEncoding:NSUTF8StringEncoding]];
}
}
This only writes one line because you rewrite the file every time you go through your loop. It is best to not writeData on the file until the loop has completed. I would also use an NSMutableString like this:
- (IBAction)saveAsFileAction:(id)sender {
if (![[NSFileManager defaultManager] fileExistsAtPath:[self dataFilePath]]) {
[[NSFileManager defaultManager] createFileAtPath: [self dataFilePath] contents:nil attributes:nil];
NSLog(#"Route creato");
}
NSMutableString *writeString = [NSMutableString stringWithCapacity:0]; //don't worry about the capacity, it will expand as necessary
for (int i=0; i<[dataArray count]; i++) {
writeString = [writeString appendString:[NSString stringWithFormat:#"%#, %#, %#, %#, %0.2f, \n",[[dataArray objectAtIndex:i]dates],[[dataArray objectAtIndex:i] time],[[dataArray objectAtIndex:i] category],[[dataArray objectAtIndex:i]place],[[dataArray objectAtIndex:i] amount]]]; //the \n will put a newline in
}
}
//Moved this stuff out of the loop so that you write the complete string once and only once.
NSLog(#"writeString :%#",writeString);
NSFileHandle *handle;
handle = [NSFileHandle fileHandleForWritingAtPath: [self dataFilePath] ];
//say to handle where's the file fo write
[handle truncateFileAtOffset:[handle seekToEndOfFile]];
//position handle cursor to the end of file
[handle writeData:[writeString dataUsingEncoding:NSUTF8StringEncoding]];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *root = [documentsDir stringByAppendingPathComponent:#"customers.csv"];
NSString *temp;
temp = [NSString stringWithFormat:#"%#", [arrCustomersName objectAtIndex:0]];
for (int i = 1; i < [arrCustomersName count]; i++) {
temp = [temp stringByAppendingFormat:#", %#", [arrCustomersName objectAtIndex:i]];
}
[temp writeToFile:root atomically:YES encoding:NSUTF8StringEncoding error:NULL];
Try this it's working for me ,
If any one want to create .csv file in swift 3
// MARK: CSV file creating
func creatCSV() -> Void {
let fileName = "Tasks.csv"
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
var csvText = "Date,Task Name,Time Started,Time Ended\n"
for task in taskArr {
let newLine = "\(task.date),\(task.name),\(task.startTime),\(task.endTime)\n"
csvText.append(newLine)
}
do {
try csvText.write(to: path!, atomically: true, encoding: String.Encoding.utf8)
} catch {
print("Failed to create file")
print("\(error)")
}
print(path ?? "not found")
}
}
For more details you can refer Detail Answer
Hopes this will help to some one .
// For CSV File :
NSMutableString *stringToWrite = [[NSMutableString alloc] init];
[stringToWrite appendString:[NSString stringWithFormat:#"First Name,Last Name,Full Name,Phone Number, Email,Job, organizationName,Note\n\n"]];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for(int i = 0 ;i<[Contact count];i++) {
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact objectAtIndex:i] valueForKey:#"firstName"] ]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact objectAtIndex:i] valueForKey:#"lastName"] ]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact valueForKey:#"userName"] objectAtIndex:i]]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact objectAtIndex:i] valueForKey:#"phoneNumber"] ]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact objectAtIndex:i] valueForKey:#"emailAddress"] ]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact objectAtIndex:i] valueForKey:#"jobTitle"] ]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#,",[[Contact objectAtIndex:i] valueForKey:#"organizationName"] ]];
[stringToWrite appendString:[NSString stringWithFormat:#"%#\n",[[Contact objectAtIndex:i] valueForKey:#"note"] ]];
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentDirectory=[paths objectAtIndex:0];
NSString *strBackupFileLocation = [NSString stringWithFormat:#"%#/%#", documentDirectory,#"ContactList.csv"];
[stringToWrite writeToFile:strBackupFileLocation atomically:YES encoding:NSUTF8StringEncoding error:nil];
});
});

Can't figure out about saving files

I am trying to save my object to the file system on an iPad, but I seem to be doing something wrong. Here is how I have archived the object:
NSString *localizedPath = [self getPlistFilePath];
NSString *fileName = [NSString stringWithFormat:#"%#.plist", character.infoName];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:character];
fileName = [fileName stringByReplacingOccurrencesOfString:#" " withString:#"_"];
localizedPath = [localizedPath stringByAppendingPathComponent:fileName];
NSLog(#"File Path: %#", localizedPath);
if(data) {
NSError *writingError;
BOOL wasWritten = [data writeToFile:localizedPath options:NSDataWritingAtomic error:&writingError];
if(!wasWritten) {
NSLog(#"%#", [writingError localizedDescription]);
}
}
Now, this creates a plist file that I can see and read on the file system. When I try to use the following to unarchive it though:
NSError *error;
NSString *directory = [self getPlistFilePath];
NSArray *files = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:directory error:&error];
NSMutableArray *characters = [[NSMutableArray alloc]init];
for(NSString *path in files) {
if(![path hasSuffix:#"plist"]) {
continue;
}
NSString *fullPath = [directory stringByAppendingPathComponent:path];
NSData *data = [NSData dataWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // get EXEC_BAD_ACCESS here...
[data release];
[characters addObject:object];
}
I get an EXEC_BAD_ACCESS error.
The IRSkillsObject conforms to the NSCoding protocol. You can see, I commented the line that I get the error on.
I am sure it's something I am doing wrong, but I just can't see it. I have tried to step through with the debugger (placing a break point in the initWithCoder: method of the object) but I don't get any errors then. In fact, it places the data in the object properly as I watch. But once it's done loading the data, it gives the error. I have tried using the retain method, but that doesn't help.
Any help that you can provide would be greatly appreciated!
You are releasing data without allocating it.
NSData *data = [NSData dataWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[data release];
So try this:
NSData *data = [[NSData alloc] initWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[data release];
When an EXEC_BAD_ACCESS error is found. Usually is because some data has been released but it is still needed in the code.
Maybe there is a property inside your IRSkillsObject not retained in -initWithCoder:

NSFileHandle fileHandleForWritingAtPath: return null!

my iPad app has a small download facility, for which I want to append the data using an NSFileHandle. The problem is the creation call only returns null file handles. What could be the problem? Here is the three lines of code that are supposed to create my file handle:
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
self.finalPath = [applicationDocumentsDirectory stringByAppendingPathComponent: self.fileName];
NSFileHandle *output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
I checked the file path, and I could see nothing wrong.
TYIA
fileHandleForWritingAtPath is not a “creation” call. The documentation explicitly states: “Return Value: The initialized file handle, or nil if no file exists at path” (emphasis added). If you wish to create the file if it does not exist, you’d have to use something like this:
NSFileHandle *output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
if(output == nil) {
[[NSFileManager defaultManager] createFileAtPath:self.finalPath contents:nil attributes:nil];
output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
}
If you want to append to the file if it already exists, use something like [output seekToEndOfFile]. Your complete code would then look as follows:
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
self.finalPath = [applicationDocumentsDirectory stringByAppendingPathComponent: self.fileName];
NSFileHandle *output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
if(output == nil) {
[[NSFileManager defaultManager] createFileAtPath:self.finalPath contents:nil attributes:nil];
output = [NSFileHandle fileHandleForWritingAtPath:self.finalPath];
} else {
[output seekToEndOfFile];
}
Get documents directory path
+(NSURL *)getDocumentsDirectoryPath
{
return [[[NSFileManager defaultManager]URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject];
}
Save text to end of the file
if file doesnt exist create it and write data
+(void)saveText:(NSString *)textTobeSaved atPath:(NSString*)fileName
{
NSString *filePath = [NSString stringWithFormat:#"%#.text",fileName];
NSString *path = [[self getDocumentsDirectoryPath].path
stringByAppendingPathComponent:filePath];
NSFileHandle *fileHandler = [NSFileHandle fileHandleForWritingAtPath:path];
if(fileHandler == nil) {
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
fileHandler = [NSFileHandle fileHandleForWritingAtPath:path];
} else {
textTobeSaved = [NSString stringWithFormat:#"\n-----------------------\n %#",textTobeSaved];
[fileHandler seekToEndOfFile];
}
[fileHandler writeData:[textTobeSaved dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandler closeFile];
}
get text from file with specified filename
+(NSString *)getTextFromFilePath:(NSString *)fileName
{
NSString *filePath = [NSString stringWithFormat:#"%#.text",fileName];
NSString *path = [[self getDocumentsDirectoryPath].path
stringByAppendingPathComponent:filePath];
NSLog(#"%#",path);
if(path!=nil)
{
NSString *savedString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
return savedString;
}else{
return #"";
}
}
Delete file
+(void)deleteFile:(NSString *)fileName
{
NSString *filePath = [NSString stringWithFormat:#"%#.text",fileName];
NSString *path = [[self getDocumentsDirectoryPath].path
stringByAppendingPathComponent:filePath];
NSFileHandle *fileHandler = [NSFileHandle fileHandleForWritingAtPath:path];
if(fileHandler != nil) {
[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
}
}