I have a Problem with that code written in Object c++ and Xcode 5:
NSLog(#"%#",pathToFile);
NSString *outputFileName = [NSTemporaryDirectory() stringByAppendingPathComponent:#"output.txt"];
FILE* fileo = fopen([outputFileName UTF8String], "w");
if (fileo) fclose(fileo);
fileo = fopen([outputFileName UTF8String], "a");
if (!fileo) { perror("fopen"); NSLog(#" Wrong"); } else { NSLog(#"Nothing Wrong"); }
//Open the PDF source file:
// FILE* filei = fopen("c:\\pdf\\somepdf.pdf", "rb");
FILE* filei = fopen([pathToFile UTF8String], "rb");
if (!filei) { perror("fopen"); NSLog(#" Wrong"); } else { NSLog(#"Nothing Wrong"); }
if (filei && fileo)
{
the Problem is that filei is every time Nil and I down't know why,!
I think the Problem is the pathtoFile:
it is: pathToFile
__NSCFString * #"file:///private/var/mobile/Applications/3D02CBE0-6A8E-4709-B6EF-B6793E19F4F4/Documents/Inbox/Published_071032-8.pdf"
0x145c53e0
The code works great on Simulator but not on the iPhone!
Has someone an idea whats wrong?
Working Directory maybe but there is no way to change it in xcode 5.
Yes seems like the Path of your file is the problem. Im even sure priced that you saw something like #"file://..." because the unix file system is based on the path directly e.g /var/mobile/.../
The next I would recommend you is to check where you define the pathToFile string. Maybe it is already out of scope because it was created on the stack because you create it within the same function/method.
Thats maybe the reason why it is NULL/ nil.
maybe a solution: create the path based on NSBundle class + don't use file:// -paths.
Let me know if it works or any additional help is required.
Thank you
regards
Related
I have been working with ESP32 and SPIFFS for a while now. My project will involve changing the content from a specific line in the file when the user need to. The file will always be saved the same format so I know which line will be changed.
My current file is stored like this:
Content inside file:
DeviceNmae
test#test.com.br
123456
button to read
uid from databa
internet ssid
internet pass
When the user changes the internet ssid in the Application, My esp32 will be reading the contento from the database and will detect the change. It will store the incoming change and update the line.
For example, I changed the data to "int ssid now", the database will read and change the "internet ssid" to "int ssid now". I would like to update the content from only that line, but I didn't find nothing on that. If I don't find the solution by updating, I will have to delete all the content from the file and create a new one only to change that line.
I append the data like this:
void funcClass::append_data(String funcName, char Text[]) {
file = SPIFFS.open("/esp_name.txt", FILE_APPEND);
while (connection_state == 1 and funcName == ""){
if (connection_state == 1 and funcName == "" and stop_loop == 0){
for (int i = 0; i < strlen(Text); i++){
char c = Text[i];
SerialBT.write(c);
}
SerialBT.write('\n');
}
stop_loop = 1;
if (SerialBT.available()){
while (SerialBT.available()) {
insert_chars = SerialBT.read();
funcName = String(funcName + insert_chars);
}
stop_loop = 0;
}
}
if (file.print(funcName)){
Serial.print("data was added: ");
Serial.println(funcName);
}else{
Serial.println("data was not added");
return;
}
file.close();
}
``
C doesn't support updating parts of a file.
You could either copy the content of your old file into a new one and change the one line before you write it to the new file.
Or maybe you have a look at the settings class if you are using the arduino framework
(or the NVS api if you are using the ESP IDF)
I have to update multiple statement in sqlite database from my iOs app. for that I have written following string.
query = #"UPDATE channels set sts = 'A' , isowner = '1' WHERE channelid=6798;UPDATE channels set sts = 'A' , isowner = '1', srl = '175' WHERE channelid=6795;";
NSLog(#"query %#",query);
[dbManager executeQuery:query];
I have create a string/statment as string with semi colon. It is worked perfectly in sqlite browser/editor, but not working in iOS app. It not throwing any error while executing statement. I don't find any mistake in my code. (as per my best knowledge). Can someone help me, why it is not working?
Thanks.
I have searched and solved it using this:
- (BOOL)executeBatch:(NSString *)sql error:(NSError**)error
{
char* errorOutput;
sqlite3 *sqlite3Database;
// Set the database file path.
NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if(openDatabaseResult == SQLITE_OK)
{
int responseCode = sqlite3_exec(sqlite3Database, [sql UTF8String], NULL, NULL, &errorOutput);
if (errorOutput != nil)
{
*error = [NSError errorWithDomain:[NSString stringWithUTF8String:errorOutput]
code:responseCode
userInfo:nil];
return false;
}
}
return true;
}
i got 2 main question.
First one; is there any database browser for sqlite that i'm using in my iOS application?
The second question - big one - is a bit complicated.
-(BOOL)createDB{
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString:
[docsDir stringByAppendingPathComponent: #"insider.db"]];
BOOL isSuccess = YES;
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt =
"create table if not exists userInfo (device_token text primary key, device_type text, carrier text, app_version text,os_version text, first_name text, last_name text,last_viewed_item text, last_added_item text, last_item_price_tag text, name_entered integer, login_screen integer, item_detailed_screen integer )";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg)
!= SQLITE_OK)
{
isSuccess = NO;
NSLog(#"Failed to create table");
}
sqlite3_close(database);
return isSuccess;
}
else {
isSuccess = NO;
NSLog(#"Failed to open/create database");
}
}
return isSuccess;
}
this is my createDB method that i call it my applicationDIdBecome active,
and i have several methods to get the items that will be saved to my database one of them ;
-(BOOL)getUserFirstName:(NSString *)firstName {
NSLog(#"User's first name is this %#",firstName);
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:#"insert into userInfo (first_name) values (\"%#\")", firstName];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
return YES;
}
else {
return NO;
}
sqlite3_reset(statement);
}
return NO;
}
i have a lot of these kind of methods ( for each columns in my create table statement)
What i want is this;
I have a backend that use mysql as database.
I need to make the last insertion row and make it JSON format so I can manipulate it and write it to my backend server.
How can i do this?
Thanks in advance.
Cheres.
Regarding SQLite tool, the database format is binary compatible across platforms. So you can just run the app in the simulator, browse to the folder with the simulator files (which varies depending upon Xcode version: it's ~/Library/Application Support/iPhone Simulator in Xcode versions prior to 6, it's ~/Library/Developer/CoreSimulator/Devices in Xcode 6) and open up the database. If your Library folder is hidden, you can unhide it from the Terminal command line, chflags nohidden ~/Library.
You can use the Mac OS X sqlite3 command line app. Many people use the free Firefox SQLite Manager add-on. I personally use Base, a relatively inexpensive SQLite tool. Use whatever you want.
Regarding retrieving results from SQLite and creating JSON from that, the easiest approach is to build a NSDictionary with the values, which you can then pass to NSJSONSerialization method dataWithJSONObject, which can build the JSON body of the request.
So, presumably you'll have some model structure that captures the content in your thirteen columns of this local table. So, insert that data in the local table, and then write a different routine that takes that model data and creates your request to POST this to the server.
You need to determine what your web service API will look like as well as how you want to POST it (e.g. NSURLConnection, NSURLSession (for iOS 7 and later), AFNetworking, etc.), but this seems well beyond the scope of this question.
A couple of unrelated observations:
If you use sqlite3_exec, supplying a pointer to a char * for the error message, remember that you're responsible for releasing that. Also, you might as well log that error message so you know why it failed:
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) {
isSuccess = NO;
NSLog(#"Failed to create table: %s", errMsg);
sqlite3_free(errMsg);
}
See the sqlite3_exec documentation for more information.
I would advise against using stringWithFormat to build your INSERT statements. Always use ? placeholders in your SQL, and then manually bind values.
Also, getUserFirstName is returning immediately if the statement was successful. So, it's not freeing the memory associated with the sqlite3_prepare_v2 (which you should do via sqlite3_finalize, not sqlite3_reset). It's also not closing the database.
-(BOOL)insertUserFirstName:(NSString *)firstName
{
BOOL success = YES;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK) {
const char *insert_stmt = "insert into userInfo (first_name) values (?)";
if (sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL) != SQLITE_OK) {
NSLog(#"prepare failure: %s", sqlite3_errmsg(database));
sqlite3_close(database);
return NO;
}
if (sqlite3_bind_text(statement, 1, [firstName UTF8String], -1, NULL) != SQLITE_OK) {
success = NO;
NSLog(#"bind 1 failure: %s", sqlite3_errmsg(database));
} else if (sqlite3_step(statement) != SQLITE_DONE) {
success = NO;
NSLog(#"step failure: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
statement = NULL;
sqlite3_close(database);
database = NULL;
}
return success;
}
Personally, I'd even advise against opening and closing the database with every SQLite call. But if you do, make sure you balance your open statements and close statements like above. You might want to also test to make sure that firstName is not nil (and if it is, call sqlite3_bind_null instead of sqlite3_bind_text).
It doesn't quite make sense to me that you're inserting only the user name. You'd presumably want to insert all of the column values at once.
When writing SQLite code, you might want to consider using FMDB, a thin Objective-C wrapper around SQLite C API, which greatly simplifies your life. When you tackle step 3, performing the sqlite3_bind_XXX calls for each of your thirteen columns, I think you'll really start to appreciate the power of something like FMDB.
I need to determine if a file in my app's documents directory is a zip file. The file name cannot be used in making this determination. So I will need to be able read the MIME type or find some other property that only applies to zips.
NOTE: A solution that requires putting the entire file into memory is not ideal as files could potentially be pretty large.
According to http://www.pkware.com/documents/casestudies/APPNOTE.TXT,
a ZIP file starts with the "local file header signature"
0x50, 0x4b, 0x03, 0x04
so it is sufficient to read the first 4 bytes to check if the file is possibly a ZIP file.
A definite decision can only be made if you actually try to extract the file.
There are many methods to read the first 4 bytes of a file. You can use NSFileHandle,
NSInputStream, open/read/close, ... . So this should only be taken as one possible example:
NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:#"/path/to/file"];
NSData *data = [fh readDataOfLength:4];
if ([data length] == 4) {
const char *bytes = [data bytes];
if (bytes[0] == 'P' && bytes[1] == 'K' && bytes[2] == 3 && bytes[3] == 4) {
// File starts with ZIP magic ...
}
}
Swift 4 version:
if let fh = FileHandle(forReadingAtPath: "/path/to/file") {
let data = fh.readData(ofLength: 4)
if data.starts(with: [0x50, 0x4b, 0x03, 0x04]) {
// File starts with ZIP magic ...
}
fh.closeFile()
}
Try this
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSString *description = [ws localizedDescriptionForType:[ws typeOfFile:#"/full/path/to/file" error:nil]];
Or for mime this
+ (NSString*) mimeTypeForFileAtPath: (NSString *) path {
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
return nil;
}
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
CFStringRef mimeType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!mimeType) {
return #"application/octet-stream";
}
return [NSMakeCollectable((NSString *)mimeType) autorelease];
}
I'd just use file, then grep if it has the text "zip" or "Zip Archive" to be safe.
if file -q $FILENAME | grep "Zip archive"; then
echo "zip";
else
echo "not zip";
fi
Since both .zip and .xlsx having the same Magic number, I couldn't find the valid zip file (if renamed).
So, I have used Apache Tika to find the exact document type.
Even if renamed the file type as zip, it finds the exact type.
Reference Apache tika use cases
Okay, here's the scenario: I have a real-time recording app using ExtAudioFileWriteAsync targeted for iOS 4.3. The first time I record with the app, it works perfectly. If I press stop, then record again, better than half the time I will get an EXC_BAD_ACCESS in AudioRingBuffer::GetTimeBounds right when recording starts.
That is to say that ExtAudioFileWriteAsync fails on GetTimeBounds when starting the second recording. Here is the bit of code that is fired when recording starts, which creates the ExtAudioFile reference:
- (void) setActive:(NSString *) file
{
if (mExtAFRef) {
ExtAudioFileDispose(mExtAFRef);
mExtAFRef = nil;
NSLog(#"mExtAFRef Disposed.");
}
if (mOutputAudioFile)
{
ExtAudioFileDispose(mOutputAudioFile);
mOutputAudioFile = nil;
NSLog(#"mOutputAudioFile Disposed.");
}
NSURL *outUrl = [NSURL fileURLWithPath:file];
OSStatus setupErr = ExtAudioFileCreateWithURL((CFURLRef)outUrl, kAudioFileWAVEType, &mOutputFormat, NULL, kAudioFileFlags_EraseFile, &mOutputAudioFile);
NSAssert(setupErr == noErr, #"Couldn't create file for writing");
setupErr = ExtAudioFileSetProperty(mOutputAudioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &audioFormat);
NSAssert(setupErr == noErr, #"Couldn't create file for format");
setupErr = ExtAudioFileWriteAsync(mOutputAudioFile, 0, NULL);
NSAssert(setupErr == noErr, #"Couldn't initialize write buffers for audio file");
isActive = TRUE;
}
Does anyone have any thoughts whatsoever on what may be causing this? I assume, given EXC_BAD_ACCESS, that it is a memory leak or something's ref count getting knocked to zero, but I can't for the life of me figure out what it might be, and the Googles are drawing a complete blank. I posted this same thing on the Apple dev forum for CoreAudio, but not a soul took pity on me, even to make a pithy comment. HALP!
EDIT: Found the problem. The error was happening when ExtAudioFileWriteAsync was trying to write a new file before the old file was "optimized." A little mutex love solved the problem.
I'm having almost the same issue on a recording app, can anyone please explain how to solve it with "A little mutex love"?
EDIT
Tnx to Chris Randall I did manage to solve my problems. This is how I implemented the mutex:
#include <pthread.h>
static pthread_mutex_t outputAudioFileLock;
then in my init:
pthread_mutex_init(&outputAudioFileLock,NULL);
and in the callback:
if (THIS.mIsRecording) {
if (0 == pthread_mutex_trylock(&outputAudioFileLock)) {
OSStatus err = ExtAudioFileWriteAsync(THIS.mRecordFile, inNumberFrames, THIS.recordingBufferList);
if (noErr != err) {
NSLog(#"ExtAudioFileWriteAsync Failed: %ld!!!", err);
} else {
}
pthread_mutex_unlock(&outputAudioFileLock);
}
}
finally in the stopRecord method:
if (mRecordFile) {
pthread_mutex_lock(&outputAudioFileLock);
OSStatus setupErr;
setupErr = ExtAudioFileDispose(mRecordFile);
mRecordFile = NULL;
pthread_mutex_unlock(&outputAudioFileLock);
NSAssert(setupErr == noErr, #"Couldn't dispose audio file");
NSLog(#"Stopping Record");
mIsRecording = NO;
}
Tnx again for the help, hope this saves someone's time.
Include pthread.h, and define pthread_mutex_t outputAudioFileLock in your constructor. Then, in your audio callback, when you want to write, do something like this (adjusting the variables according to what you're using):
if (0 == pthread_mutex_trylock(&outputAudioFileLock)) {
OSStatus err = ExtAudioFileWriteAsync(mOutputAudioFile, frames, bufferList);
if (noErr != err) {
NSLog(#"ExtAudioFileWriteAsync Failed: %ld!!!", err);
} else {
}
pthread_mutex_unlock(&outputAudioFileLock);
}
The pthread_mutex_trylock checks to see if the thread is locked (and thus "optimizing"). If it is not, it then allows the write. I then wrap both the audio file setup (as seen above) and the audio file cleanup like so, so that the thread is locked when the file system is doing anything that would cause the AudioRingBuffer BAD_ACCESS error:
pthread_mutex_lock(&outputAudioFileLock);
OSStatus setupErr;
setupErr = ExtAudioFileDispose(mOutputAudioFile);
mOutputAudioFile = NULL;
pthread_mutex_unlock(&outputAudioFileLock);
NSAssert(setupErr == noErr, #"Couldn't dispose audio file");
This locks the setup and cleanup threads so that you can't write to a file that is being "optimized," which is the source of the error. Hope this helps!
EDIT: I do my audio callback in the Obj-C part of the audio controller; if you're doing it in the C++ part, this would be structured quite a bit differently; perhaps someone else can answer that?