The process to create such an archive file is fairly straightforward. You'll want to read in the raw bytes of every input file, writing them to a single in-memory output buffer as you go.
You will also need to keep track of where in the output buffer you begin to write each file. Without this "table of contents" information, it will be very difficult to get the individual file bytes out of the archive later.
Once you've copied all the input files into the buffer, open the final output file and write the table-of-contents information into it. Then write the output buffer that contains the raw file bytes.
Then, to read data from the archive file later, you can open it and read the table-of-contents chunk. That will give you the offsets (relative to the end of the table-of-contents) of each file in the archive.
The above will get you a basic implementation. There are, of course, many variations you can make on this theme, for example by storing more file metadata, or providing support for buffering the I/O operations in some fashion, or precomputing the table of contents data based on just the file sizes so you can stream the archive output to disk instead of requiring it to all exist in memory at once. Whether or not these are relevant to you depend on your specific needs.
Some very straightforward and naive pseudo-code in a C#-like language might be:
var archive = new List<byte>();
var contents = new Dictionary<string, int>()
var files = /* a list of all input files that will be in the archive */
foreach (var file in files) {
var bytes = ReadAllBytes(file);
// We're about to write the file to the archive, so store the offset.
contents[file] = archive.Count;
// Write the actual bytes.
archive.AddRange(bytes);
}
// Now write the final archive.
var output = /* name of the output file */
foreach (var pair in contents) {
WriteToFile(output, pair.Key);
WriteToFile(output, pair.Value);
}
WriteToFile(output, archive);