Запись двоичных данных в файл, буквально

#php #filesystems #binaryfiles #binary-data

#php #файловые системы #двоичные файлы #двоичные данные

Вопрос:

У меня есть массив целых чисел

 Array
(
    [0] => Array
        (
            [0] => 1531412763
            [1] => 1439959339
            [2] => 76
            [3] => 122
            [4] => 200
            [5] => 4550
            [6] => 444
        )
...
  

И так далее, я полагаю, если я посмотрю на это так, как если бы это была база данных — элементами самого внешнего массива являются строки, а элементами внутренних массивов являются столбцы.

Я хочу сохранить эту информацию в файл, чтобы я мог получить ее позже, но я хочу сохранить ее как двоичные данные для экономии места. В принципе, если я запишу первое целое число из примера 1531412763 в файл, оно займет 10 байт, но если бы я мог сохранить его как целое число со знаком, оно заняло бы 4 байта.

Я просмотрел ряд других ответов, которые все предлагают использовать fwrite , и я не могу понять, как использовать их таким образом?

Комментарии:

1. упаковать ?

2. Если вам действительно нужно сэкономить место, почему бы не сжать данные тоже? Возможно, на этом этапе.

3. @Zimmi да, это именно то, что мне было нужно, но нужно ли мне вызывать pack каждое отдельное значение или есть более простой способ?

4. Вы не можете pack($array) , как есть. Но вы можете предоставить pack функции несколько аргументов и использовать repeaters ( * ) после форматирования. Что-то вроде pack('i*', $int_1, $int_2,....) упаковки нескольких целых чисел. Вам придется обрабатывать свой массив в соответствии с желаемым форматом.

5. @Zimmi Итак, в основном, как я должен это сделать, это pack('LLSSSQ', $row[0], ..., $row[6]) записать это в виде одной строки в файле, и при чтении мне нужно использовать unpack тот же формат, который вернет мне массив обратно. Это идеально, вы можете использовать это как ответ для кого-то другого в моей ситуации.

Ответ №1:

Для записи двоичных данных в файл вы можете использовать функции pack() и unpack() . Pack создаст двоичную строку. Поскольку результатом является строка, вы можете объединить целые числа в одну строку. Затем запишите эту строку в виде строки в свой файл.

Таким образом, вы можете легко прочитать, с file() помощью которого файл будет помещен в массив строк. Затем просто unpack() каждую строку, и вы получаете свой исходный массив обратно.

Что-то вроде этого :

 $arr = array(
    array ( 1531412763, 1439959339 ),
    array ( 123, 456, 789 ),
);

$file_w = fopen('binint', 'w ');

// Creating file content : concatenation of binary strings 
$bin_str = '';
foreach ($arr as $inner_array_of_int) {
    foreach ($inner_array_of_int as $num) {
        // Use of i format (integer). If you want to change format
        // according to the value of $num, you will have to save the
        // format too.
        $bin_str .= pack('i', $num);
    }

    $bin_str .= "n";
}

fwrite($file_w, $bin_str);
fclose($file_w);


// Now read and test. $lines_read will contain an array like the original.
$lines_read = [];
// We use file function to read the file as an array of lines.
$file_r = file('binint');

// Unpack all lines
foreach ($file_r as $line) {
    // Format is i* because we may have more than 1 int in the line
    // If you changed format while packing, you will have to unpack with the
    // corresponding same format
    $lines_read[] = unpack('i*', $line);
}

var_dump($lines_read);
  

Комментарии:

1. И если каждая строка содержит одинаковое количество элементов, вам даже не нужны новые строки, вам просто нужно вычислить длину строки при преобразовании в двоичный файл, а затем fread($handle, $length) .

2. Абсолютно! И оптимизируйте формат, как вы предложили в своем последнем комментарии в вопросе.

3. Используя этот метод, вместо хранения обычного текста мне удалось сэкономить довольно много места. От 2.72GB до 400MB , это 6.8 сокращение в разы!