文章851
标签121
分类10

JS 字节格式化工具

在开发中,我们经常需要处理文件大小、网络流量或其他以字节为单位的数据。直接使用字节数可能不够直观,因此将其转换为更易于理解的格式(如 KB、MB、GB 等)是非常有用的。本文将介绍如何使用 JavaScript 编写一个字节格式化工具。

1. 字节格式化的必要性

在许多应用场景中,字节数的直接表示方式并不直观。例如,1,024 字节可能对用户来说没有意义,但当我们将其格式化为 1 KB 时,信息就变得清晰明了。通过格式化,我们可以:

  • 提高用户体验:以用户更易理解的方式展示数据。
  • 使数据更具可读性:避免使用过大的数字,使数据更易于比较和理解。

2. 字节格式化工具的基本思路

我们可以创建一个简单的 JavaScript 函数,将字节数转换为人类可读的格式。该函数将:

  1. 接收字节数作为输入。
  2. 根据字节数的大小选择合适的单位(B、KB、MB、GB 等)。
  3. 格式化输出,保留适当的小数位。

3. 示例代码

以下是一个简单的字节格式化工具的实现:

function formatBytes(bytes, decimals = 2) {
    if (bytes === 0) return '0 Bytes';

    const k = 1024; // 每个单位的字节数
    const dm = decimals < 0 ? 0 : decimals; // 小数位数
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; // 单位数组

    const i = Math.floor(Math.log(bytes) / Math.log(k)); // 计算当前单位索引
    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; // 格式化输出
}

// 示例用法
console.log(formatBytes(1024)); // 输出 "1 KB"
console.log(formatBytes(1234)); // 输出 "1.21 KB"
console.log(formatBytes(123456789)); // 输出 "117.74 MB"
console.log(formatBytes(0)); // 输出 "0 Bytes"

3.1 代码解析

  • 参数说明

    • bytes:要格式化的字节数。
    • decimals:可选参数,指定小数位数,默认为 2。
  • 逻辑介绍

    1. 如果字节数为 0,返回 "0 Bytes"。
    2. 定义每个单位的字节数(k)和单位数组(sizes)。
    3. 使用 Math.log() 计算当前字节数对应的单位索引。
    4. 使用 parseFloat()toFixed() 保留指定的小数位,返回最终的格式化字符串。

4. 在实际应用中的使用

4.1 文件上传

在文件上传功能中,可以使用该工具来展示用户文件的大小,使其更易于理解。

4.2 网络请求

在显示网络请求的流量时,可以使用字节格式化工具来展示下载和上传的字节数,提高用户体验。

4.3 数据存储

在展示数据库或存储系统的使用情况时,使用格式化后的字节数可以帮助用户更好地理解数据占用情况。

5. 结论

字节格式化工具是一个简单而实用的工具,可以帮助我们以更易于理解的方式展示字节数。通过上述示例,您可以轻松地在 JavaScript 中实现字节格式化功能,提升用户体验。

PHP 脚本开启守护进程方式

在许多应用场景中,特别是需要长期运行的服务或任务,使用守护进程(Daemon)是一种有效的解决方案。守护进程是一种在后台运行的进程,不依赖于用户的登录会话。本文将介绍如何在 PHP 中创建和管理守护进程。

1. 什么是守护进程?

守护进程是一种在后台运行的程序,通常用于处理系统服务、监控任务或定时作业。与普通进程不同,守护进程在没有用户交互的情况下独立运行,通常在系统启动时启动,或者在用户登录后启动。

2. PHP 中创建守护进程的基本步骤

在 PHP 中创建守护进程通常涉及以下几个步骤:

  1. fork 进程:创建子进程,使父进程退出。
  2. 改变工作目录:将工作目录更改为根目录,以避免阻止卸载文件系统。
  3. 关闭标准输入/输出:关闭标准输入、输出和错误输出,防止与终端交互。
  4. 运行主要任务:在子进程中执行需要的任务。

3. PHP 守护进程示例

以下是一个简单的 PHP 脚本,演示如何创建一个守护进程:

<?php

function daemonize() {
    // 创建子进程
    $pid = pcntl_fork();
    if ($pid < 0) {
        exit("无法创建子进程\n");
    }
    if ($pid > 0) {
        // 父进程退出
        exit();
    }

    // 设置新的会话
    if (posix_setsid() < 0) {
        exit("无法创建新的会话\n");
    }

    // 更改工作目录
    chdir('/');

    // 关闭标准输入、输出和错误输出
    fclose(STDIN);
    fclose(STDOUT);
    fclose(STDERR);

    // 重新打开标准输入、输出和错误输出
    $STDIN = fopen('/dev/null', 'r');
    $STDOUT = fopen('/dev/null', 'a');
    $STDERR = fopen('/dev/null', 'a');

    // 运行主要任务
    while (true) {
        // 这里可以执行需要长期运行的任务
        file_put_contents('/tmp/daemon.log', date('Y-m-d H:i:s') . " Daemon is running\n", FILE_APPEND);
        sleep(5); // 每5秒执行一次
    }
}

// 启动守护进程
daemonize();

3.1 代码解析

  1. 创建子进程:使用 pcntl_fork() 创建子进程。如果返回值小于 0,表示创建失败;如果返回值大于 0,表示当前进程是父进程,会退出。
  2. 设置新的会话:使用 posix_setsid() 创建新的会话,确保守护进程与控制终端分离。
  3. 更改工作目录:使用 chdir('/') 将工作目录更改为根目录,避免阻止卸载文件系统。
  4. 关闭标准输入/输出:关闭标准输入、输出和错误输出,防止与终端交互。然后将它们重定向到 /dev/null
  5. 运行主要任务:在无限循环中执行需要的任务,例如写入日志文件。

4. 启动和管理守护进程

4.1 启动守护进程

将上述脚本保存为 my_daemon.php,运行以下命令启动守护进程:

php my_daemon.php &

使用 & 将其放到后台运行。

4.2 查看日志

守护进程将在 /tmp/daemon.log 中写入日志,可以使用以下命令查看日志内容:

tail -f /tmp/daemon.log

4.3 停止守护进程

可以使用 kill 命令停止守护进程,首先找到进程 ID(PID):

ps aux | grep my_daemon.php

然后使用 kill 命令停止进程:

kill <PID>

5. 注意事项

  • 使用 pcntl 扩展:确保 PHP 安装了 pcntl 扩展(在某些环境中需要手动安装)。
  • 资源管理:确保守护进程妥善处理资源,避免内存泄漏或文件描述符消耗。
  • 信号处理:可以使用 pcntl_signal() 处理进程信号,以便优雅地停止守护进程。

6. 结论

在 PHP 中创建守护进程可以有效地处理长期运行的任务和服务。通过遵循上述步骤和示例,您可以轻松地在 PHP 中实现并管理守护进程。

PHP 序列化选择

在 PHP 开发中,序列化是将数据结构或对象转换为可存储或传输的格式的过程。正确选择序列化方法可以提高性能、可读性和数据安全性。本文将探讨 PHP 中的序列化方法,包括它们的优缺点,以及在不同场景中的最佳实践。

1. 什么是序列化?

序列化是将数据结构或对象转换为字符串的过程,以便保存到文件、数据库或通过网络传输。反序列化则是将字符串转换回原始数据结构或对象的过程。

2. PHP 中的序列化方法

PHP 提供了几种序列化方法,最常见的有:

2.1 serialize()unserialize()

使用场景:适用于 PHP 内部数据结构和对象。

优点

  • 简单易用,适合快速开发。
  • 能够序列化复杂的数据结构,如数组和对象。

缺点

  • 生成的字符串不具可读性。
  • 对于跨语言的数据交换不友好。
  • 安全性风险:反序列化不可信的数据可能导致代码执行漏洞。

示例

$data = ['name' => 'Alice', 'age' => 30, 'is_admin' => false];
$serializedData = serialize($data);
$unserializedData = unserialize($serializedData);

2.2 JSON 序列化

使用场景:适用于与其他语言或系统的数据交互。

优点

  • 生成的字符串具有良好的可读性。
  • 与 JavaScript 兼容,易于与前端交互。
  • 安全性较高,反序列化时不会执行 PHP 代码。

缺点

  • 不支持 PHP 特有的数据类型(如资源、对象)。
  • 处理大型数据时性能相对较低。

示例

$data = ['name' => 'Alice', 'age' => 30, 'is_admin' => false];
$jsonData = json_encode($data);
$decodedData = json_decode($jsonData, true);

2.3 MessagePack

使用场景:适用于需要高性能和节省存储空间的场景。

优点

  • 二进制格式,序列化和反序列化速度快。
  • 占用空间小,适合网络传输。

缺点

  • 不易于调试(不具可读性)。
  • 对某些数据类型支持有限。

示例

# 安装 MessagePack 扩展
pecl install msgpack
$data = ['name' => 'Alice', 'age' => 30, 'is_admin' => false];
$packedData = msgpack_pack($data);
$unpackedData = msgpack_unpack($packedData);

2.4 XML 序列化

使用场景:适用于需要与 XML 系统或协议集成的场景。

优点

  • 人类可读性强,易于调试。
  • 广泛支持,许多系统和语言都能处理 XML。

缺点

  • 占用空间大,性能较低。
  • 处理复杂数据结构时较为繁琐。

示例

$data = ['name' => 'Alice', 'age' => 30, 'is_admin' => false];
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($data, [$xml, 'addChild']);
$xmlString = $xml->asXML();

3. 如何选择合适的序列化方法?

选择序列化方法时,可以考虑以下因素:

  1. 数据类型:如果需要序列化复杂的 PHP 对象,serialize() 是一个不错的选择;如果与其他系统交互,JSON 或 XML 更为合适。
  2. 性能需求:在对速度和存储空间有严格要求的情况下,MessagePack 是最佳选择。
  3. 可读性:如果需要调试或记录数据,JSON 和 XML 提供更好的可读性。
  4. 安全性:避免使用 unserialize() 解码不可信的数据,JSON 是更安全的选择。

4. 结论

在 PHP 中,选择合适的序列化方法至关重要。通过了解各种序列化选项的优缺点,您可以根据具体需求做出明智的决策。在实际开发中,根据数据的性质和应用场景选择合适的序列化方式,可以提高应用的性能和安全性。

文件锁:解决高并发数据安全问题

在高并发环境下,确保数据的安全性和一致性至关重要。文件锁是一种有效的机制,可以防止多个进程或线程同时访问同一文件,导致数据冲突和不一致。本文将介绍如何在 PHP 中实现文件锁,并分享相关的示例代码。

1. 什么是文件锁?

文件锁用于控制对文件的访问,它允许一个进程在操作文件时获得对该文件的独占访问权,从而阻止其他进程同时进行写操作。

  • 共享锁:允许多个进程同时读取文件,但不允许写入。
  • 独占锁:只允许一个进程对文件进行写操作,其他进程无法读取或写入。

2. PHP 中的文件锁

在 PHP 中,可以使用 flock() 函数来实现文件锁。该函数允许您在打开的文件上获取锁,并通过参数控制锁的类型。

2.1 使用示例

以下是一个简单的 PHP 示例,演示如何使用文件锁来安全地写入文件。

<?php
function lock_file($filename) {
    // 打开文件
    $file = fopen($filename, 'a'); // 以追加模式打开文件
    if ($file === false) {
        die("无法打开文件: $filename");
    }

    // 获取独占锁
    if (flock($file, LOCK_EX)) {
        // 执行文件操作
        fwrite($file, "Hello, World!\n");
        sleep(5); // 模拟长时间操作
        // 释放锁
        flock($file, LOCK_UN);
    } else {
        echo "无法获取文件锁\n";
    }

    // 关闭文件
    fclose($file);
}

// 调用函数
lock_file('example.txt');
?>

2.2 代码解释

  1. 打开文件:使用 fopen() 函数以追加模式打开文件。
  2. 获取锁:使用 flock() 函数尝试获取独占锁(LOCK_EX)。
  3. 写入数据:在获得锁后,使用 fwrite() 函数写入数据,并模拟长时间操作。
  4. 释放锁:写入完成后,使用 flock() 释放锁(LOCK_UN)。
  5. 关闭文件:最后,使用 fclose() 关闭文件。

3. 高并发场景下的应用

3.1 日志记录

在高并发的 Web 应用中,多个请求可能同时写入日志文件。使用文件锁可以确保日志条目按顺序写入,避免日志文件混乱。

3.2 配置文件更新

当多个进程需要同时读取和修改配置文件时,文件锁可以确保配置的一致性,防止多个进程同时对同一配置文件进行写操作。

3.3 数据处理

在处理数据文件时,文件锁可以确保数据在读取和写入期间不被其他进程修改,从而保护数据完整性。

4. 注意事项

  • 死锁:在使用文件锁时,需注意死锁的发生,确保锁的获取和释放逻辑清晰。
  • 性能:频繁的加锁和解锁可能影响性能,尽量减少锁的持有时间。
  • 跨平台:不同操作系统对文件锁的支持可能不同,使用时需考虑兼容性。

5. 结论

文件锁是一种有效的解决高并发数据安全问题的机制,通过合理使用文件锁,可以确保数据的一致性和完整性。在 PHP 中,使用 flock() 函数可以简单地实现文件锁。希望本文能帮助您理解文件锁的应用及其实现。

Nginx Redis Lua 模块试用体验

在现代 web 开发中,Nginx 作为高性能的反向代理服务器广泛应用,而 Lua 语言因其轻量和灵活性备受青睐。将 Nginx、Lua 和 Redis 结合在一起,可以构建高效的动态 web 应用。本文将分享我在使用 Nginx Redis Lua 模块过程中的体验与实践。

1. 背景介绍

2024-09-06T01:52:28.png

1.1 Nginx

Nginx 是一个高性能的 HTTP 和反向代理服务器,因其处理静态文件和并发请求的能力而广受欢迎。

1.2 Lua

Lua 是一种轻量级的脚本语言,适用于嵌入式开发,因其灵活性和性能而被广泛使用。

1.3 Redis

Redis 是一个开源的高性能键值数据库,常用于缓存和会话存储,能够提供快速的数据访问。

2. 环境搭建

2.1 安装 Nginx 和 Lua

首先,我们需要安装 Nginx 和 Lua 模块。可以使用 OpenResty,它是一个基于 Nginx 的分发版本,内置了 Lua 支持。

# 安装 OpenResty
sudo apt update
sudo apt install openresty

2.2 安装 Redis

接下来,安装 Redis 数据库:

sudo apt install redis-server

启动 Redis 服务:

sudo systemctl start redis

3. 配置 Nginx

3.1 编辑 Nginx 配置文件

/etc/nginx/nginx.conf 中,添加 Lua 和 Redis 的配置。例如:

http {
    lua_shared_dict my_cache 10m;  # 定义共享内存

    server {
        listen 8080;

        location / {
            default_type 'text/html';
            content_by_lua_block {
                local redis = require 'resty.redis'
                local red = redis:new()

                red:set_timeout(1000)  -- 1秒超时
                local ok, err = red:connect('127.0.0.1', 6379)

                if not ok then
                    ngx.say("failed to connect: ", err)
                    return
                end

                -- 从 Redis 获取数据
                local res, err = red:get("my_key")
                if not res or res == ngx.null then
                    ngx.say("no data found")
                else
                    ngx.say("Data from Redis: ", res)
                end

                -- 关闭 Redis 连接
                red:close()
            }
        }
    }
}

3.2 测试配置

保存配置后,测试 Nginx 配置文件:

sudo nginx -t

如果没有错误,重新加载 Nginx:

sudo systemctl reload nginx

4. 使用 Lua 操作 Redis

4.1 设置数据

在 Redis 中设置一些数据用于测试:

redis-cli set my_key "Hello, Nginx with Lua and Redis!"

4.2 访问 Nginx

在浏览器中访问 http://localhost:8080,您应该能够看到从 Redis 中获取的数据:

Data from Redis: Hello, Nginx with Lua and Redis!

5. 性能测试与优化

5.1 性能测试

使用 ab 工具(Apache Benchmark)进行压力测试:

ab -n 1000 -c 100 http://localhost:8080/

观察 Nginx 的响应时间和请求成功率,确保系统能够处理高并发请求。

5.2 优化建议

  • 连接池:使用 Redis 连接池来减少连接建立的开销。
  • 错误处理:添加更完善的错误处理机制,确保系统健壮性。
  • 缓存策略:根据业务逻辑设计合适的缓存策略,提升性能。

6. 总结

通过将 Nginx、Lua 和 Redis 结合在一起,我们能够构建出高效且灵活的 web 应用。Lua 的嵌入式特性使得 Nginx 可以快速响应动态请求,而 Redis 则提供了快速的数据存储和访问能力。希望本文的分享能够帮助您更好地理解和应用 Nginx Redis Lua 模块。

">