How to read only "N" bytes from a specified file?
4 Answers
If you want random access to the contents of the file in a manner similar to having loaded it via NSData but without actually reading everything into memory, you can use memory mapping. Doing so means that the file on disk becomes treated as a section of virtual memory, and will be paged in and out just like regular virtual memory.
NSError * error = nil;
NSData * theData = [NSData dataWithContentsOfFile: thePath
options: NSMappedRead
error: &error];
If you don't care about getting filesystem error details, you can just use:
NSData * theData = [NSData dataWithContentsOfMappedFile: thePath];
Then you would just use NSData's -getBytes:range:
method to pull out specific pieces of data, and only the relevant parts of the file will actually be read from permanent storage; they'll also be eligible to be paged out too.

- 11,166
- 2
- 33
- 40
-
1That's a cool idea, I wouldn't have thought of that. Remember that when mapping files to memory, it's arguably even more critical to make sure you properly release the object, since leaks have a broader effect. – Quinn Taylor Jun 22 '09 at 01:03
-
2do you know if this is any different from NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:thePath]; [stream read:theBuffer maxLength:255]; ? i am assuming they are identical – valexa Sep 28 '11 at 18:07
-
2NSInputStream will read chunks from the filesystem discretely. If you're accessing the file in sequential fashion, streaming is good. If you need random access, then NSFileHandle or a mapped data object are the way to go, the latter being more optimized for random access overall. – Jim Dovey Oct 24 '11 at 16:16
-
1FYI, Warning: `dataWithContentsOfMappedFile:` is deprecated: first deprecated in iOS 8.0 - Use `+dataWithContentsOfURL:options:error:` and `NSDataReadingMappedIfSafe` or `NSDataReadingMappedAlways` instead. – GabLeRoux Jun 22 '17 at 00:38
-
1@GabLeRoux— thanks for reminding me of that. I'd also suggest `NSDataReadingUncached` unless you're likely to read the file multiple times. – Jim Dovey Sep 11 '17 at 20:38
-[NSFileHandle readDataOfLength:].
NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *fileData = [handle readDataOfLength:N];
[handle closeFile];

- 15,530
- 13
- 76
- 177

- 95,783
- 15
- 211
- 370
-
-
4[[NSFileHandle fileHandleForReadingAtPath:path] readDataOfLength:length] – Peter Hosey Jun 01 '09 at 19:59
-
If you're following the comment above, be sure to call -closeFile on the handle after. – Dov Mar 28 '15 at 14:07
If you want to avoid reading the entire file, you can just use the standard C I/O functions:
#include <stdio.h>
...
FILE *file = fopen("the-file.dat", "rb");
if(file == NULL)
; // handle error
char theBuffer[1000]; // make sure this is big enough!!
size_t bytesRead = fread(theBuffer, 1, 1000, file);
if(bytesRead < 1000)
; // handle error
fclose(file);

- 390,455
- 97
- 512
- 589
-
I wonder if this will correctly resolve Finder aliases in the path given? – neoneye Jun 01 '09 at 18:33
-
It should; I believe that Finder aliases are just symbolic links, and stdio can handle symlinks properly. To figure out the target of a symlink istead of reading the target file, one can use the readlink(2) function, see http://linux.die.net/man/2/readlink . – Adam Rosenfield Jun 01 '09 at 18:56
-
Finder aliases are not symbolic links. Finder supports both, but creates aliases. – Peter Hosey Jun 01 '09 at 19:01
-
Ah ok, never mind then. This will not work with Finder aliases then. – Adam Rosenfield Jun 01 '09 at 19:05
Open the file:
NSData *fileData = [NSData dataWithContentsOfFile:fileName];
Read the bytes you want:
int bytes[1000];
[fileData getBytes:bytes length:sizeof(int) * 1000];

- 26,829
- 3
- 55
- 74
-
I don't know cocoa, but: why are you using `int` rather than `char`? – poundifdef Jun 01 '09 at 18:25
-
5In this example the entire file has to be read before reading those N bytes. In my case when the file is approx 900 MB this method seems to be a bit to "hardcore" – Grzegorz Kazulak Jun 01 '09 at 18:30
-
An int is at least two bytes (usually 4), and originally I did write it to use char, which is generally one byte. I usually think it's best not to assume that any type has a specific number of bytes. That's probably attributable to my UNIX days :-) – Alex Jun 01 '09 at 18:33
-
There's also getBytes:range: method that takes a range to skip to the section of the file you're interested in. – Alex Jun 01 '09 at 18:34
-
-
Alex: That still reads the entire file, then excerpts it. You're paying both for memory and time to read the whole file and for time to copy the sub-range. – Peter Hosey Jun 01 '09 at 19:01