Concatenating files to a virtual file on Linux

On a Linux system, is there any way to concatenate a series of files into one exposed file for reading and writing while not actually taking up another N bytes of disk space? I was hoping for something like mounting these files via loopback/devmapper to accomplish this.

I have a problem where there are split binary files that can get quite large. I don't want to double my space requirements with massive disk IO just to temporarily read / write contents from these files by cating them all together into one enormous file.

I found this project here, but it seems to have a very specific use case and also depends on perl


You can do that by combining loop devices and device mapper, thanks to "everything is a file". But with one limitation: The file size cannot be changed (as you cannot increase block devices by writing to them). So if you want to append data then you have to create a bigger block device and overwrite the appended dummy data.

# for testing, Create 4 files
echo foo | dd of=block0 cbs=512 conv=block
echo bar | dd of=block1 cbs=512 conv=block
echo bat | dd of=block2 cbs=512 conv=block
echo baz | dd of=block3 cbs=512 conv=block
# Create a loop device for each of the 4 files
losetup /dev/loop0 block0
losetup /dev/loop1 block1
losetup /dev/loop2 block2
losetup /dev/loop3 block3
# Create a device map named "test" using those loop devices
(
    echo "0 1 linear /dev/loop0 0"
    echo "1 1 linear /dev/loop1 0"
    echo "2 1 linear /dev/loop2 0"
    echo "3 1 linear /dev/loop3 0"
) | dmsetup create test
$EDITOR /dev/mapper/test # use overwrite mode only

For extending the file you may create a big sparse file and use that as additional device.


The answer provided by Hauke Laging is good, but one should note the first number in those echo lines doesn't just automatically increment by one. In this example it does, but if your block0, block1 etc were greater than one block in length, those numbers must increment by the size of the previous echo line. A clean example of this provided by kernel.org is below, assuming $1 is your /dev/loop0 and $2 is your /dev/loop1:

#!/bin/sh
# Join 2 devices together
1=/dev/loop0
2=/dev/loop1
size1=`blockdev --getsz $1`
size2=`blockdev --getsz $2`
echo "0 $size1 linear $1 0
$size1 $size2 linear $2 0" | dmsetup create joined

Source: https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/linear.html


This could be done using named pipe in Linux.

Assume you have files named file0, file1, file2, file3, file4, file5

# create a name pipe
$ mkfifo mynewfile
# cat to named file
$ cat file{0..5} > mynewfile &

In C programatically you can do

mkfifo(mynewfile , 0777);
system("cat file{0..5} > mynewfile");

Then use then use mynewfile as us you would read from normal file.

mynewfile is FIFO file