I need somewhere to save and then to retrieve Sint16 (2 bytes).
I get:
SInt16* frames = (SInt16*)inBuffer->mAudioData;
and want to save &frames[i] somewhere (NSMutableData?) that could later easily retrieve. I tried to save like this (in cycle):
[recordedData appendBytes:&frames[i] length:1];
and retrieve:
SInt16* framesRetrieve ;
//sets up mybytes buffer and reads in data from myData
framesRetrieve = (SInt16*)malloc([mutableData framesRetrieve]);
[mutableData getBytes:framesRetrieve];
But this return not the same as i put into.
So what could be a solution ?
thanks.
You need to know the length of the data and then you can store the whole buffer in an NSMutableData object:
To store:
SInt16 *frames = ...;
NSUInteger length = ...; // Assuming number of elements in frames, not bytes!
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];
[data appendBytes:(const void *)frames length:length * sizeof(SInt16)];
To retrieve:
SInt16 *frames = (SInt16 *)[data bytes];
NSUInteger length = [data length] / sizeof(SInt16);
You are only copying one byte from a 2 byte variable. Try appending both bytes to the NSMutableData at once.
[recordedData appendBytes: frames length:sizeof(SInt16)];
Related
I'm needing to get all of the bytes from an NSData object after the 12th index.
So far I have
const char* fileBytes = (const char*)[imageData bytes];
NSUInteger length = [imageData length];
NSUInteger index;
NSMutableString *byteString = [[NSMutableString alloc] init];
[SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:#"bytes: %#", imageData.description]];
for (index = 12; index<length; index++) { //Grabba returns a 12 byte header.
char aByte = fileBytes[index];
[byteString appendString:[NSString stringWithFormat:#"%x", aByte]];
}
But what I'd really like to do is create a const char* and just append each byte at index 12 till the end to it. How can I append bytes to a series of bytes?
What you need to do is use some standard C library calls. You know how many bytes there are in the NSData object, so you can alloc the storage you need and then memcpy all the bytes from the 12th one on.
NSUInteger length = [data length];
char* theBytes = malloc(sizeof(char)*(length-11));
memcpy(theBytes,fileBytes+11,length-11);
theBytes cannot be a const char* because of course it is not constant until after you have called memcpy.
Remember to call free when you are done with the string.
I read file from fcntl(fd, F_GLOBAL_NOCACHE, 1); to read file from Disk not from Cache. After reading file, i can only get string data. Now i want to after reading file, i get byte data of file to NSMutableData. How can i do that? Thanks in advance.
if (fd)
{
fcntl(fd, F_GLOBAL_NOCACHE, 1);
NSMutableData* myData = [[NSMutableData alloc] init];
while(YES)
{
// store the length before addition
NSUInteger previousLength = [myData length];
// increase the length so we can write more bytes
[myData increaseLengthBy:300];
// read bytes from stream directly at the end of our data
size_t len = fread([myData mutableBytes] + previousLength, 300, 1, fd);
// set data length
[myData setLength:previousLength + len];
// if end-of-file exit the loop
if (len == 0) {
break;
}
[myData appendBytes:buffer length:len];
}
// use your 'myData'
NSLog(#"dataFile: %#",myData);
[myData release];
Please give me suggestions? thanks
UPDATE2:
Now i have another problem: i want to read file direct from disk not from Cache. I used below code but it seem not work, it still read from Cache :
NSString *url= [NSString stringWithFormat:#"%#/demo.abc"];
const char *c_sd_url = [url UTF8String];
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
FILE * fd = fopen(c_sd_url, "rb");
if (fd)
{
fcntl(fd, F_GLOBAL_NOCACHE, 1);
fseek(fd, 0, SEEK_END);
long sz = ftell(fd);
fseek(fd, 0, SEEK_SET);
char *buf = malloc(sz);
NSLog(#"before %s",buf);
assert(buf != NULL);
assert(fread(buf, sz, 1, fd) == 1);
NSLog(#"after %s",buf);
NSMutableData *data= [NSMutableData dataWithBytesNoCopy:buf length:sz freeWhenDone:YES];
NSLog(#"%#",data);
}
I used fcntl(fd, F_GLOBAL_NOCACHE, 1); after fopen(). Please give me any suggestion. Thanks much
char in C is guaranteed to be 1 byte at least by standard.
What is an unsigned char?
So you can treat char* as byte-array with proper size multiplication, and you can pass it to -[NSData initWithBytes:length:] method.
char buffer[300];
NSData* data0 = [[NSData alloc] initWithBytes:buffer length:300 * sizeof(char)];
There're several initializer methods, so check them out for your needs. See NSMutableData for procedural style use.
Or you can use NSData method as like #HotLicks said.
NSData* data0 = [NSData dataWithContentsOfFile:#"somefile" options:NSDataReadingUncached error:NULL];
I guess Hot Licks is right, you probably want to simply use -[NSData dataWithContentsOfFile:], but in the case you want to use C level APIs, you can do:
#define MY_BUFFER_SIZE 1024
FILE * fd = fopen(c_sd_url, "rb");
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char buffer[MY_BUFFER_SIZE];
if (fd)
{
fcntl(fd, F_GLOBAL_NOCACHE, 1);
// if you can predict the capacity it's better for performance
NSMutableData* myData = [NSMutableData dataWithCapacity:1024];
while(fgets(buffer, MY_BUFFER_SIZE, fd) != NULL)
{
[myData appendBytes:buffer length:strlen(buffer)];
}
}
// use your 'myData'
[pool release];
Updated: to avoid useless copy of buffer data, and following H2CO3's comment:
It's better to avoid to write data to a buffer and then copy it to the NSMutableData, we can use -[NSData mutableBytes] to access directly the underlying C structure. Also, H2CO3 is completely right, using fread is much better since it gives us the length of the bytes read.
#define MY_BUFFER_SIZE 1024
FILE * fd = fopen(c_sd_url, "rb");
if (fd)
{
fcntl(fd, F_GLOBAL_NOCACHE, 1);
// if you can predict the capacity it's better for performance
NSMutableData* myData = [[NSMutableData alloc] init];
while(YES)
{
// store the length before addition
NSUInteger previousLength = [myData length];
// increase the length so we can write more bytes
[myData increaseLengthBy:MY_BUFFER_SIZE];
// read bytes from stream directly at the end of our data
size_t len = fread([myData mutableBytes] + previousLength, 1, MY_BUFFER_SIZE, fd);
// set data length
[myData setLength:previousLength + len];
// if end-of-file exit the loop
if (len == 0) {
break;
}
}
// use your 'myData'
NSLog(#"myData: %#", [[NSString alloc] initWithData:myData encoding:NSASCIIStringEncoding]);
[myData release];
}
If you want to have a \0 terminated NSData, just add at the end:
[myData appendBytes:"\0" length:1];
Good luck ;)
How can I iterate through [NSData bytes] one by one and append them to an NSMutableString or print them using NSLog()?
Rather than appending bytes to a mutable string, create a string using the data:
// Be sure to use the right encoding:
NSString *result = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
If you really want to loop through the bytes:
NSMutableString *result = [NSMutableString string];
const char *bytes = [myData bytes];
for (int i = 0; i < [myData length]; i++)
{
[result appendFormat:#"%02hhx", (unsigned char)bytes[i]];
}
Update! Since iOS 7, there's a new, preferred way to iterate through all of the bytes in an NSData object.
Because an NSData can now be composed of multiple disjoint byte array chunks under the hood, calling [NSData bytes] can sometimes be memory-inefficient, because it needs to flatten all of the underlying chunks into a single byte array for the caller.
To avoid this behavior, it's better to enumerate bytes using the enumerateByteRangesUsingBlock: method of NSData, which will return ranges of the existing underlying chunks, which you can access directly without needing to generate any new array structures. Of course, you'll need to be careful not to go poking around inappropriately in the provided C-style array.
NSMutableString* resultAsHexBytes = [NSMutableString string];
[data enumerateByteRangesUsingBlock:^(const void *bytes,
NSRange byteRange,
BOOL *stop) {
//To print raw byte values as hex
for (NSUInteger i = 0; i < byteRange.length; ++i) {
[resultAsHexBytes appendFormat:#"%02x", ((uint8_t*)bytes)[i]];
}
}];
I have a NSData item that is holding a bunch of ints. How do I go about getting them out and into an NSArray?
The memory structure in the NSData is 32-bit int in little-endian order, one right after the other.
Sorry for the basic question, but still learning the obj-c way of doing things :)
You can use the functions defined in OSByteOrder.h to deal with endianness. Aside from that quirk, this is really just a matter of grabbing the byte buffer and iterating over it.
// returns an NSArray containing NSNumbers from an NSData
// the NSData contains a series of 32-bit little-endian ints
NSArray *arrayFromData(NSData *data) {
void *bytes = [data bytes];
NSMutableArray *ary = [NSMutableArray array];
for (NSUInteger i = 0; i < [data length]; i += sizeof(int32_t)) {
int32_t elem = OSReadLittleInt32(bytes, i);
[ary addObject:[NSNumber numberWithInt:elem]];
}
return ary;
}
Sounds like there are cleaner ways to do what you're trying to do, but this should work:
NSData *data = ...; // Initialized earlier
int *values = [data bytes], cnt = [data length]/sizeof(int);
for (int i = 0; i < cnt; ++i)
NSLog(#"%d\n", values[i]);
This answer is very similar to other answers above, but I found it instructive to play with casting the NSData bytes back to an int32_t[] array. This code works correctly on a little-endian processor (x64 in my case) but would be silently wrong on big-endian (PPC) because the byte representation would be big-endian.
int32_t raw_data[] = {0,1,2,3,4,5,6,7,8,9,10};
printf("raw_data has %d elements\n", sizeof(raw_data)/sizeof(*raw_data));
NSData *data = [NSData dataWithBytes:(void*)raw_data length:sizeof(raw_data)];
printf("data has %d bytes\n", [data length]);
int32_t *int_data_out = (int32_t*) [data bytes];
for (int i=0; i<[data length]/4; ++i)
printf("int %d = %d\n", i, int_data_out[i]);
[data release];
One possible solution below.
To take endianness into account, look up Core Endian Reference in the XCode doc set (you probably would use EndianS32_LtoN (32 bit litte endian to native endianness)).
int mem[]= {0x01, 0x02, 0x03, 0x04, 0xff};
NSData * data = [NSData dataWithBytes:mem length:sizeof(mem)*sizeof(int)];
NSMutableArray * ar = [NSMutableArray arrayWithCapacity:10];
/* read ints out of the data and add them to the array, one at a time */
int idx=0;
for(;idx<[data length]/sizeof(int);idx+=sizeof(int))
[ar addObject:[NSNumber numberWithInt:*(int *)([data bytes] + idx)]];
NSLog(#"Array:%#", ar);
ex:
NSData *data = [NSData dataWithContentsOfFile:filePath];
int len = [data length];
if len = 10000,
i hope i can convert 1000 to a NSData look like
char hoperesult[] = {0x10, 0x27, 0x00, 0x00}
and hoperesult[] must always 4 Bytes
So you want the length in 4 little-endian bytes, correct? I think this will do it:
unsigned int len = [data length];
uint32_t little = (uint32_t)NSSwapHostIntToLittle(len);
NSData *byteData = [NSData dataWithBytes:&little length:4];
(Note that most network protocols use big-endian, but you showed little-endian so that's what this does.)
I'm not 100% sure what you mean here, but I think you are attempting to fill hoperesult with the values found in the file at 'filePath'.
struct _hoperesult {
char data[4];
} *hoperesult;
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
NSRange offset;
offset.location = 0;
offset.length = sizeof(_hoperesult);
NSData *hoperesultData;
while( (offset.location + offset.length) < len ) {
hoperesultData = [data subdataWithRange:offset];
// the equivalent of your char hoperesult[] content...
hoperesult = [hoperesultData bytes]
}
An instance of NSData can return a pointer to the actual bytes of data using the "bytes" method. It returns a (const void *). You could in theory simply cast [data bytes] to a char * and use the offset directly; or you can do like in the above code and return smaller chucks of NSData.
Hope that helps!