Плоские файловые базы данных

Каковы лучшие практики создания структур баз данных с плоскими файлами в PHP?

Существует множество более зрелых фреймворков для плоских файлов PHP, которые я пытаюсь реализовать с синтаксисом запросов, подобным SQL, который в большинстве случаев является лучшим для моих целей. (Я бы просто использовал базу данных на этом этапе).

Есть ли какие-нибудь изящные приемы, позволяющие получить хорошую производительность и функции с небольшими накладными расходами на код?

Я хотел бы добавить, что здесь есть пакет для База данных плоских файловgithub.com/tmarois/Filebase Я знаю, что это старый вопрос, но этот пакет является самой последней сборкой и поддерживается, плюс полный функций, который почти не включает.

tmarois 06.09.2017 16:24

Я разрабатываю CMS и использую текстовую базу данных с обычным текстовым файлом. На изготовление и повторный перелом уходит много часов, но это работает отлично. Запросы будут выполняться намного быстрее с полностью проиндексированной и оптимизированной базой данных. Однако я избегаю запросов, сохраняя метаданные и тщательно организовывая и структурируя их. Когда мне нужны данные, я получаю их без for loop (если я не использую все данные в папке), поэтому он работает намного быстрее, чем база данных. Я бы подробно остановился и дал очень хороший ответ, но, к сожалению, этот вопрос закрыт.

Dan Bray 21.10.2018 20:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
125
2
62 377
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Одна из структур, которую я рассматриваю, - это платформа для ведения блогов. Поскольку практически любое возможное представление данных, которое вы хотели бы, было бы отсортировано по дате, я думал об этой структуре:

Один каталог на узел содержимого:

./content/YYYYMMDDHHMMSS/

Поддиректории каждого узла, включая

/tags  
/authors  
/comments  

А также простые текстовые файлы в каталоге узлов для содержимого до и после рендеринга и тому подобное.

Это позволило бы простому вызову PHP glob() (и, возможно, обращению массива результатов) запрашивать практически все в структуре содержимого:

glob("content/*/tags/funny");  

Вернет пути, включая все статьи с меткой "смешно".

Ответ принят как подходящий

Ну какова природа плоских баз данных. Они большие или маленькие. Это простые массивы с массивами в них? если это что-то простое, скажем, профили пользователей, созданные как таковые:

$user = array("name" => "dubayou", 
              "age" => 20,
              "websites" => array("dubayou.com","willwharton.com","codecream.com"),
              "and_one" => "more");

и сохранить или обновить запись в БД для этого пользователя.

$dir = "../userdata/";  //make sure to put it bellow what the server can reach.
file_put_contents($dir.$user['name'],serialize($user));

и загрузить записывать для пользователя

function &get_user($name){
    return unserialize(file_get_contents("../userdata/".$name));
}

но, опять же, эта реализация будет зависеть от приложения и характера базы данных, которая вам нужна.

Вы можете рассмотреть SQLite. Это почти так же просто, как плоские файлы, но вы получаете механизм SQL для запросов. Это тоже хорошо работает с PHP.

SQLite был встроен в 5.0+ по умолчанию, но со скидкой (!), Начиная с PHP 5.4+ !!! На момент написания этой статьи в июле 2012 года SQLite по умолчанию больше не будет работать в современных системах. Официальное заявление здесь

Sliq 27.07.2012 01:59

Установка драйвера SQLite PDO довольно тривиальна, если у вас есть доступ к серверу. В Ubuntu / Debian, на котором запущен Apache2, просто выполните apt-get install php5-sqlite service apache2 restart

siliconrockstar 02.12.2012 19:39

В ответ на комментарий от @Sliq утверждение, что «SQLite был ... прекращен», является своего рода правдой: расширение с именем «SQLite» было прекращено, а «SQLite3» теперь включен по умолчанию. php.net/manual/en/sqlite.installation.php "Начиная с PHP 5.0 это расширение было связано с PHP. Начиная с PHP 5.4, это расширение доступно только через PECL." php.net/manual/en/sqlite3.installation.php "Расширение SQLite3 включено по умолчанию с PHP 5.3.0." «Это расширение некоторое время было расширением PECL, но эта версия рекомендуется только для экспериментального использования».

Paul van Leeuwen 04.12.2016 23:25

Вы не ответили на вопрос

JG Estiot 18.07.2019 18:08

Если вы собираетесь использовать плоский файл для сохранения данных, используйте XML для структурирования данных. PHP имеет встроенный XML-парсер.

И следуйте правилам XML для удобочитаемости, иначе вы можете использовать сериализацию, json или что-то еще.

Ben 23.06.2016 10:10

Очень плохой совет. XML никогда не следует использовать. Это жирная аберрация.

JG Estiot 18.07.2019 18:10

@JGEstiot Хотите объяснить дальше?

UncaughtTypeError 26.07.2019 16:27

Если вам нужен удобочитаемый результат, вы также можете использовать этот тип файла:

ofaurax|27|male|something|
another|24|unknown||
...

Таким образом, у вас есть только один файл, вы можете легко его отлаживать (и вручную исправлять), вы можете добавлять поля позже (в конце каждой строки), а код PHP прост (для каждой строки, разделенный в соответствии с |).

Однако недостатком является то, что вы должны анализировать весь файл для поиска чего-либо (если у вас есть миллионы записей, это не нормально), и вы должны обрабатывать разделитель в данных (например, если ник WaR | ordz).

На мой взгляд, использование «Базы данных плоских файлов» в том смысле, в котором вы имеете в виду (и ответ, который вы приняли), не обязательно лучший способ действовать. Во-первых, использование serialize() и unserialize() может вызвать БОЛЬШИЕ головные боли, если кто-то войдет и отредактирует файл (фактически, они могут помещать произвольный код в вашу «базу данных» для выполнения каждый раз).

Лично я бы сказал - почему бы не заглянуть в будущее? Было так много раз, что у меня были проблемы, потому что я создавал свои собственные "проприетарные" файлы, и проект взорвался до такой степени, что ему нужна база данных, и я думаю: Я написал это для начала "базы данных" - потому что рефакторинг кода требует слишком много времени и усилий.

Из этого я узнал, что будущая проверка моего приложения, чтобы, когда оно становится больше, мне не приходилось тратить дни на рефакторинг, - это путь вперед. Как мне это сделать?

SQLite. Он работает как база данных, использует SQL и довольно легко перейти на MySQL (особенно, если вы используете абстрактные классы для управления базой данных, как это делаю я!)

Фактически, особенно с методом «принятого ответа», он может резко сократить использование памяти вашим приложением (вам не нужно загружать все «ЗАПИСИ» в PHP)

Это правда. serialize() может быть очень полезен и для этого. Я думаю, что уловка для создания жизнеспособной системы заключается в том, чтобы найти способ индексировать узлы данных, не убивая себя сложностью.

saint_groceon 01.08.2008 18:58

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

AaA 14.08.2020 12:16

У вас есть пример использования?

felwithe 04.09.2020 07:44

Вот код, который мы используем для Лилины:

<?php
/**
 * Handler for persistent data files
 *
 * @author Ryan McCue <[email protected]>
 * @package Lilina
 * @version 1.0
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */

/**
 * Handler for persistent data files
 *
 * @package Lilina
 */
class DataHandler {
    /**
     * Directory to store data.
     *
     * @since 1.0
     *
     * @var string
     */
    protected $directory;

    /**
     * Constructor, duh.
     *
     * @since 1.0
     * @uses $directory Holds the data directory, which the constructor sets.
     *
     * @param string $directory 
     */
    public function __construct($directory = null) {
        if ($directory === null)
            $directory = get_data_dir();

        if (substr($directory, -1) != '/')
            $directory .= '/';

        $this->directory = (string) $directory;
    }

    /**
     * Prepares filename and content for saving
     *
     * @since 1.0
     * @uses $directory
     * @uses put()
     *
     * @param string $filename Filename to save to
     * @param string $content Content to save to cache
     */
    public function save($filename, $content) {
        $file = $this->directory . $filename;

        if (!$this->put($file, $content)) {
            trigger_error(get_class($this) . " error: Couldn't write to $file", E_USER_WARNING);
            return false;
        }

        return true;
    }

    /**
     * Saves data to file
     *
     * @since 1.0
     * @uses $directory
     *
     * @param string $file Filename to save to
     * @param string $data Data to save into $file
     */
    protected function put($file, $data, $mode = false) {
        if (file_exists($file) && file_get_contents($file) === $data) {
            touch($file);
            return true;
        }

        if (!$fp = @fopen($file, 'wb')) {
            return false;
        }

        fwrite($fp, $data);
        fclose($fp);

        $this->chmod($file, $mode);
        return true;

    }

    /**
     * Change the file permissions
     *
     * @since 1.0
     *
     * @param string $file Absolute path to file
     * @param integer $mode Octal mode
     */
    protected function chmod($file, $mode = false){
        if (!$mode)
            $mode = 0644;
        return @chmod($file, $mode);
    }

    /**
     * Returns the content of the cached file if it is still valid
     *
     * @since 1.0
     * @uses $directory
     * @uses check() Check if cache file is still valid
     *
     * @param string $id Unique ID for content type, used to distinguish between different caches
     * @return null|string Content of the cached file if valid, otherwise null
     */
    public function load($filename) {
        return $this->get($this->directory . $filename);
    }

    /**
     * Returns the content of the file
     *
     * @since 1.0
     * @uses $directory
     * @uses check() Check if file is valid
     *
     * @param string $id Filename to load data from
     * @return bool|string Content of the file if valid, otherwise null
     */
    protected function get($filename) {
        if (!$this->check($filename))
            return null;

        return file_get_contents($filename);
    }

    /**
     * Check a file for validity
     *
     * Basically just a fancy alias for file_exists(), made primarily to be
     * overriden.
     *
     * @since 1.0
     * @uses $directory
     *
     * @param string $id Unique ID for content type, used to distinguish between different caches
     * @return bool False if the cache doesn't exist or is invalid, otherwise true
     */
    protected function check($filename){
        return file_exists($filename);
    }

    /**
     * Delete a file
     *
     * @param string $filename Unique ID
     */
    public function delete($filename) {
        return unlink($this->directory . $filename);
    }
}

?>

Он хранит каждую запись в виде отдельного файла, который, как мы обнаружили, достаточно эффективен для использования (ненужные данные не загружаются и их быстрее сохранять).

ИМХО, у вас есть два ... эээ, три варианта, если вы хотите избежать домашнего пивоварения:

  1. SQLite

Если вы знакомы с PDO, вы можете установить драйвер PDO, поддерживающий SQLite. Никогда не использовал его, но я много использовал PDO с MySQL. Я собираюсь попробовать это в текущем проекте.

  1. XML

Сделано это много раз для относительно небольших объемов данных. XMLReader - это легкий класс в стиле курсора с упреждающим чтением. SimpleXML упрощает чтение XML-документа в объект, к которому вы можете получить доступ, как и к любому другому экземпляру класса.

  1. JSON (обновить)

Хороший вариант для небольших объемов данных, просто чтение / запись файла и json_decode / json_encode. Не уверен, что PHP предлагает структуру для навигации по дереву JSON, не загружая все это в память.

Хорошие мысли. Почему не JSON?

Machado 08.10.2020 01:35

Потому что, когда я писал этот пост, JSON еще не был чем-то вроде лол

siliconrockstar 10.10.2020 04:53

Вау, хе-хе, извини, я не видел дату публикации раньше. Так что приятно, JSON по-прежнему может быть добавлен, если кому-то нравится увеличивать ответ.

Machado 12.10.2020 04:18

Я написал две простые функции, предназначенные для хранения данных в файле. Судите сами, пригодится ли это в данном случае. Дело в том, чтобы сохранить переменную php (если это массив, строка или объект) в файл.

<?php
function varname(&$var) {
    $oldvalue=$var;
    $var='AAAAB3NzaC1yc2EAAAABIwAAAQEAqytmUAQKMOj24lAjqKJC2Gyqhbhb+DmB9eDDb8+QcFI+QOySUpYDn884rgKB6EAtoFyOZVMA6HlNj0VxMKAGE+sLTJ40rLTcieGRCeHJ/TI37e66OrjxgB+7tngKdvoG5EF9hnoGc4eTMpVUDdpAK3ykqR1FIclgk0whV7cEn/6K4697zgwwb5R2yva/zuTX+xKRqcZvyaF3Ur0Q8T+gvrAX8ktmpE18MjnA5JuGuZFZGFzQbvzCVdN52nu8i003GEFmzp0Ny57pWClKkAy3Q5P5AR2BCUwk8V0iEX3iu7J+b9pv4LRZBQkDujaAtSiAaeG2cjfzL9xIgWPf+J05IQ==';
    foreach($GLOBALS as $var_name => $value) {
        if ($value === 'AAAAB3NzaC1yc2EAAAABIwAAAQEAqytmUAQKMOj24lAjqKJC2Gyqhbhb+DmB9eDDb8+QcFI+QOySUpYDn884rgKB6EAtoFyOZVMA6HlNj0VxMKAGE+sLTJ40rLTcieGRCeHJ/TI37e66OrjxgB+7tngKdvoG5EF9hnoGc4eTMpVUDdpAK3ykqR1FIclgk0whV7cEn/6K4697zgwwb5R2yva/zuTX+xKRqcZvyaF3Ur0Q8T+gvrAX8ktmpE18MjnA5JuGuZFZGFzQbvzCVdN52nu8i003GEFmzp0Ny57pWClKkAy3Q5P5AR2BCUwk8V0iEX3iu7J+b9pv4LRZBQkDujaAtSiAaeG2cjfzL9xIgWPf+J05IQ==')
        {
            $var=$oldvalue;
            return $var_name;
        }
    }
    $var=$oldvalue;
    return false;
}

function putphp(&$var, $file=false)
    {
    $varname=varname($var);
    if (!$file)
    {
        $file=$varname.'.php';
    }
    $pathinfo=pathinfo($file);
    if (file_exists($file))
    {
        if (is_dir($file))
        {
            $file=$pathinfo['dirname'].'/'.$pathinfo['basename'].'/'.$varname.'.php';
        }
    }
    file_put_contents($file,'<?php'."\n$".$varname.'='.var_export($var, true).";\n");
    return true;
}

Мне это показалось интересным, и это ЛУЧШЕ, потому что мы просто выгружаем форматированный массив в файл. Нам не нужно строить его заново, просто прочтите. Кроме того, редактировать переменные немного проще. Я никогда не буду использовать это для хранения больших данных, но я нашел практичным хранить программные модули без базы данных. Спасибо.

m3nda 24.01.2015 02:08

Просто укажу на потенциальную проблему с базой данных плоских файлов в этом типе системы:

data|some text|more data

row 2 data|bla hbalh|more data

...так далее

Проблема в том, что данные ячейки содержат символ "|" или "\ n", данные будут потеряны. Иногда было бы проще разделить на комбинации букв, которые большинство людей не использовали бы.

Например:

Разделитель колонки: #$% (Shift+345)

Разделитель строк: ^&* (Shift+678)

Текстовый файл: test data#$%blah blah#$%^&*new row#$%new row data 2

Затем используйте: explode("#$%", $data); use foreach, the explode again to separate columns

Или что-нибудь в этом роде. Кроме того, я мог бы добавить, что базы данных с плоскими файлами хороши для систем с небольшими объемами данных (например, менее 20 строк), но становятся огромными потребителями памяти для больших баз данных.

Хорошие моменты. Сделав еще один шаг вперед, PHP может очень легко сериализовать JSON. Экранирование ввода намного проще, поэтому вам не нужно использовать забавные комбинации строк, чтобы файл был более читабельным.

Cypher 23.09.2014 21:17

Это вдохновляет как практическое решение:
https://github.com/mhgolkar/FlatFire
Он использует несколько стратегий для обработки данных ...
[Скопировано из файла Readme]

Бесплатные, структурированные или смешанные

- STRUCTURED
Regular (table, row, column) format.
[DATABASE]
/   \
TX  TableY
    \_____________________________
    |ROW_0 Colum_0 Colum_1 Colum_2|
    |ROW_1 Colum_0 Colum_1 Colum_2|
    |_____________________________|
- FREE
More creative data storing. You can store data in any structure you want for each (free) element, its similar to storing an array with a unique "Id".
[DATABASE]
/   \
EX  ElementY (ID)
    \________________
    |Field_0 Value_0 |
    |Field_1 Value_1 |
    |Field_2 Value_2 |
    |________________|
recall [ID]: get_free("ElementY") --> array([Field_0]=>Value_0,[Field_1]=>Value_1...
- MIXD (Mixed)
Mixed databases can store both free elements and tables.If you add a table to a free db or a free element to a structured db, flat fire will automatically convert FREE or SRCT to MIXD database.
[DATABASE]
/   \
EX  TY

Другие вопросы по теме